Skip to content

Package: HeapMemoryManager$RecyclableByteBufferWrapper

HeapMemoryManager$RecyclableByteBufferWrapper

nameinstructionbranchcomplexitylinemethod
HeapMemoryManager.RecyclableByteBufferWrapper(ByteBuffer)
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
dispose()
M: 5 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
initialize(ByteBuffer)
M: 7 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
recycle()
M: 8 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * Copyright (c) 2010, 2020 Oracle and/or its affiliates. All rights reserved.
3: *
4: * This program and the accompanying materials are made available under the
5: * terms of the Eclipse Public License v. 2.0, which is available at
6: * http://www.eclipse.org/legal/epl-2.0.
7: *
8: * This Source Code may also be made available under the following Secondary
9: * Licenses when the conditions for such availability set forth in the
10: * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
11: * version 2 with the GNU Classpath Exception, which is available at
12: * https://www.gnu.org/software/classpath/license.html.
13: *
14: * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15: */
16:
17: package org.glassfish.grizzly.memory;
18:
19: import java.nio.ByteBuffer;
20: import java.nio.ByteOrder;
21: import java.nio.charset.Charset;
22: import java.util.Arrays;
23:
24: import org.glassfish.grizzly.Buffer;
25: import org.glassfish.grizzly.Cacheable;
26: import org.glassfish.grizzly.ThreadCache;
27: import org.glassfish.grizzly.monitoring.MonitoringConfig;
28: import org.glassfish.grizzly.monitoring.MonitoringUtils;
29:
30: /**
31: * A {@link WrapperAware} {@link MemoryManager} implementation for managing {@link HeapBuffer} instances.
32: *
33: * @since 2.0
34: */
35: public class HeapMemoryManager extends AbstractMemoryManager<HeapBuffer> implements WrapperAware {
36:
37: private static final ThreadCache.CachedTypeIndex<TrimmableHeapBuffer> CACHE_IDX = ThreadCache.obtainIndex(TrimmableHeapBuffer.class,
38: Integer.getInteger(HeapMemoryManager.class.getName() + ".thb-cache-size", 8));
39:
40: private static final ThreadCache.CachedTypeIndex<RecyclableByteBufferWrapper> BBW_CACHE_IDX = ThreadCache.obtainIndex(RecyclableByteBufferWrapper.class,
41: Integer.getInteger(HeapMemoryManager.class.getName() + ".rbbw-cache-size", 2));
42:
43: public HeapMemoryManager() {
44: super();
45: }
46:
47: public HeapMemoryManager(final int maxBufferSize) {
48: super(maxBufferSize);
49: }
50:
51: // ---------------------------------------------- Methods from MemoryManager
52:
53: /**
54: * {@inheritDoc}
55: */
56: @Override
57: public HeapBuffer allocate(final int size) {
58: return allocateHeapBuffer(size);
59: }
60:
61: /**
62: * {@inheritDoc}
63: */
64: @Override
65: public HeapBuffer allocateAtLeast(final int size) {
66: return allocateHeapBufferAtLeast(size);
67: }
68:
69: /**
70: * {@inheritDoc}
71: */
72: @Override
73: public HeapBuffer reallocate(final HeapBuffer oldBuffer, final int newSize) {
74: return reallocateHeapBuffer(oldBuffer, newSize);
75: }
76:
77: /**
78: * {@inheritDoc}
79: */
80: @Override
81: public void release(final HeapBuffer buffer) {
82: releaseHeapBuffer(buffer);
83: }
84:
85: /**
86: * {@inheritDoc}
87: */
88: @Override
89: public boolean willAllocateDirect(int size) {
90: return false;
91: }
92:
93: /**
94: * {@inheritDoc}
95: */
96: @Override
97: public MonitoringConfig<MemoryProbe> getMonitoringConfig() {
98: return monitoringConfig;
99: }
100:
101: /**
102: * {@inheritDoc}
103: */
104: @Override
105: public ThreadLocalPool createThreadLocalPool() {
106: return new HeapBufferThreadLocalPool(this);
107: }
108:
109: /**
110: * {@inheritDoc}
111: */
112: @Override
113: protected Object createJmxManagementObject() {
114: return MonitoringUtils.loadJmxObject("org.glassfish.grizzly.memory.jmx.HeapMemoryManager", this, HeapMemoryManager.class);
115: }
116:
117: // ----------------------------------------------- Methods from WrapperAware
118:
119: /**
120: * {@inheritDoc}
121: */
122: @Override
123: public HeapBuffer wrap(final byte[] data) {
124: return createTrimAwareBuffer(data, 0, data.length);
125: }
126:
127: /**
128: * {@inheritDoc}
129: */
130: @Override
131: public HeapBuffer wrap(final byte[] data, final int offset, final int length) {
132: return createTrimAwareBuffer(data, offset, length);
133: }
134:
135: /**
136: * {@inheritDoc}
137: */
138: @Override
139: public HeapBuffer wrap(final String s) {
140: return wrap(s, Charset.defaultCharset());
141: }
142:
143: /**
144: * {@inheritDoc}
145: */
146: @Override
147: public HeapBuffer wrap(final String s, final Charset charset) {
148: return wrap(s.getBytes(charset));
149: }
150:
151: /**
152: * {@inheritDoc}
153: */
154: @Override
155: public Buffer wrap(final ByteBuffer byteBuffer) {
156: if (byteBuffer.hasArray()) {
157: return wrap(byteBuffer.array(), byteBuffer.arrayOffset() + byteBuffer.position(), byteBuffer.remaining());
158: } else {
159: return createByteBufferWrapper(byteBuffer);
160: }
161: }
162:
163: // ------------------------------------------------------- Protected Methods
164:
165: /**
166: * Creates a new HeapBuffer with a a specified size.
167: *
168: * @param size size of buffer created
169: * @return
170: */
171: protected HeapBuffer allocateHeapBuffer(final int size) {
172: if (size > maxBufferSize) {
173: // Don't use pool
174: return createTrimAwareBuffer(size);
175: }
176:
177: final ThreadLocalPool<HeapBuffer> threadLocalCache = getHeapBufferThreadLocalPool();
178: if (threadLocalCache != null) {
179: final int remaining = threadLocalCache.remaining();
180:
181: if (remaining == 0 || remaining < size) {
182: reallocatePoolBuffer();
183: }
184:
185: return (HeapBuffer) allocateFromPool(threadLocalCache, size);
186: } else {
187: return createTrimAwareBuffer(size);
188: }
189: }
190:
191: protected HeapBuffer allocateHeapBufferAtLeast(final int size) {
192: if (size > maxBufferSize) {
193: // Don't use pool
194: return createTrimAwareBuffer(size);
195: }
196:
197: final ThreadLocalPool<HeapBuffer> threadLocalCache = getHeapBufferThreadLocalPool();
198: if (threadLocalCache != null) {
199: int remaining = threadLocalCache.remaining();
200:
201: if (remaining == 0 || remaining < size) {
202: reallocatePoolBuffer();
203: remaining = threadLocalCache.remaining();
204: }
205:
206: return (HeapBuffer) allocateFromPool(threadLocalCache, remaining);
207: } else {
208: return createTrimAwareBuffer(size);
209: }
210: }
211:
212: protected HeapBuffer reallocateHeapBuffer(HeapBuffer oldHeapBuffer, int newSize) {
213: if (oldHeapBuffer.capacity() >= newSize) {
214: return oldHeapBuffer;
215: }
216:
217: final ThreadLocalPool<HeapBuffer> memoryPool = getHeapBufferThreadLocalPool();
218: if (memoryPool != null) {
219: final HeapBuffer newBuffer = memoryPool.reallocate(oldHeapBuffer, newSize);
220:
221: if (newBuffer != null) {
222: ProbeNotifier.notifyBufferAllocatedFromPool(monitoringConfig, newSize - oldHeapBuffer.capacity());
223:
224: return newBuffer;
225: }
226: }
227:
228: final HeapBuffer newHeapBuffer = allocateHeapBuffer(newSize);
229: oldHeapBuffer.flip();
230: return newHeapBuffer.put(oldHeapBuffer);
231: }
232:
233: protected final void releaseHeapBuffer(final HeapBuffer heapBuffer) {
234: final ThreadLocalPool<HeapBuffer> memoryPool = getHeapBufferThreadLocalPool();
235: if (memoryPool != null) {
236:
237: if (memoryPool.release(heapBuffer.clear())) {
238: ProbeNotifier.notifyBufferReleasedToPool(monitoringConfig, heapBuffer.capacity());
239: }
240: }
241:
242: }
243:
244: // --------------------------------------------------------- Private Methods
245:
246: private void reallocatePoolBuffer() {
247: final byte[] heap = new byte[maxBufferSize];
248: ProbeNotifier.notifyBufferAllocated(monitoringConfig, maxBufferSize);
249:
250: final HeapBufferThreadLocalPool threadLocalCache = getHeapBufferThreadLocalPool();
251: if (threadLocalCache != null) {
252: threadLocalCache.reset(heap, 0, maxBufferSize);
253: }
254: }
255:
256: TrimmableHeapBuffer createTrimAwareBuffer(final int length) {
257: final byte[] heap = new byte[length];
258: ProbeNotifier.notifyBufferAllocated(monitoringConfig, length);
259:
260: return createTrimAwareBuffer(heap, 0, length);
261: }
262:
263: TrimmableHeapBuffer createTrimAwareBuffer(final byte[] heap, final int offset, final int length) {
264:
265: final TrimmableHeapBuffer buffer = ThreadCache.takeFromCache(CACHE_IDX);
266: if (buffer != null) {
267: buffer.initialize(this, heap, offset, length);
268: return buffer;
269: }
270:
271: return new TrimmableHeapBuffer(this, heap, offset, length);
272: }
273:
274: private ByteBufferWrapper createByteBufferWrapper(final ByteBuffer underlyingByteBuffer) {
275:
276: final RecyclableByteBufferWrapper buffer = ThreadCache.takeFromCache(BBW_CACHE_IDX);
277: if (buffer != null) {
278: buffer.initialize(underlyingByteBuffer);
279: return buffer;
280: }
281:
282: return new RecyclableByteBufferWrapper(underlyingByteBuffer);
283: }
284:
285: /**
286: * Gets the thread local buffer pool If the pool is not an instance of HeapBufferThreadLocalPool then null is returned
287: *
288: * @return
289: */
290: @SuppressWarnings("unchecked")
291: private static HeapBufferThreadLocalPool getHeapBufferThreadLocalPool() {
292: final ThreadLocalPool pool = getThreadLocalPool();
293: return pool instanceof HeapBufferThreadLocalPool ? (HeapBufferThreadLocalPool) pool : null;
294: }
295:
296: // ---------------------------------------------------------- Nested Classes
297:
298: /**
299: * Information about thread associated memory pool.
300: */
301: private static final class HeapBufferThreadLocalPool implements ThreadLocalPool<HeapBuffer> {
302: /**
303: * Memory pool
304: */
305: private byte[] pool;
306:
307: private int leftPos;
308: private int rightPos;
309:
310: private int start;
311: private int end;
312:
313: private final ByteBuffer[] byteBufferCache;
314: private int byteBufferCacheSize = 0;
315: private final HeapMemoryManager mm;
316:
317: public HeapBufferThreadLocalPool(final HeapMemoryManager mm) {
318: this(mm, 8);
319: }
320:
321: public HeapBufferThreadLocalPool(final HeapMemoryManager mm, final int maxByteBufferCacheSize) {
322: byteBufferCache = new ByteBuffer[maxByteBufferCacheSize];
323: this.mm = mm;
324: }
325:
326: @Override
327: public HeapBuffer allocate(final int size) {
328: final HeapBuffer allocated = mm.createTrimAwareBuffer(pool, rightPos, size);
329: if (byteBufferCacheSize > 0) {
330: allocated.byteBuffer = byteBufferCache[--byteBufferCacheSize];
331: byteBufferCache[byteBufferCacheSize] = null;
332: }
333:
334: rightPos += size;
335: return allocated;
336: }
337:
338: @Override
339: public HeapBuffer reallocate(final HeapBuffer heapBuffer, final int newSize) {
340: final int diff;
341:
342: if (isLastAllocated(heapBuffer) && remaining() >= (diff = newSize - heapBuffer.cap)) {
343:
344: rightPos += diff;
345: heapBuffer.cap = newSize;
346: heapBuffer.lim = newSize;
347:
348: return heapBuffer;
349: }
350:
351: return null;
352: }
353:
354: @Override
355: public boolean release(final HeapBuffer heapBuffer) {
356: boolean canCacheByteBuffer = heapBuffer.byteBuffer != null && byteBufferCacheSize < byteBufferCache.length;
357:
358: final boolean result;
359:
360: if (isLastAllocated(heapBuffer)) {
361: rightPos -= heapBuffer.cap;
362:
363: if (leftPos == rightPos) {
364: leftPos = rightPos = start;
365: }
366:
367: result = true;
368: } else if (isReleasableLeft(heapBuffer)) {
369: leftPos += heapBuffer.cap;
370: if (leftPos == rightPos) {
371: leftPos = rightPos = start;
372: }
373:
374: result = true;
375: } else if (wantReset(heapBuffer.cap)) {
376: reset(heapBuffer);
377:
378: result = true;
379: } else {
380: canCacheByteBuffer = canCacheByteBuffer && pool == heapBuffer.heap;
381: result = false;
382: }
383:
384: if (canCacheByteBuffer) {
385: byteBufferCache[byteBufferCacheSize++] = heapBuffer.byteBuffer;
386: }
387:
388: return result;
389: }
390:
391: @Override
392: public void reset(final HeapBuffer heapBuffer) {
393: reset(heapBuffer.heap, heapBuffer.offset, heapBuffer.cap);
394: }
395:
396: public void reset(final byte[] heap, final int offset, final int capacity) {
397: if (pool != heap) {
398: clearByteBufferCache();
399: pool = heap;
400: }
401:
402: leftPos = rightPos = start = offset;
403: end = offset + capacity;
404: }
405:
406: @Override
407: public boolean wantReset(final int size) {
408: return size - remaining() > 1024;
409: }
410:
411: @Override
412: public boolean isLastAllocated(final HeapBuffer oldHeapBuffer) {
413: return oldHeapBuffer.heap == pool && oldHeapBuffer.offset + oldHeapBuffer.cap == rightPos;
414: }
415:
416: private boolean isReleasableLeft(final HeapBuffer oldHeapBuffer) {
417: return oldHeapBuffer.heap == pool && oldHeapBuffer.offset == leftPos;
418: }
419:
420: @Override
421: public HeapBuffer reduceLastAllocated(final HeapBuffer heapBuffer) {
422: final int newPos = heapBuffer.offset + heapBuffer.cap;
423:
424: ProbeNotifier.notifyBufferReleasedToPool(mm.monitoringConfig, rightPos - newPos);
425:
426: rightPos = newPos;
427:
428: return null;
429: }
430:
431: @Override
432: public int remaining() {
433: return end - rightPos;
434: }
435:
436: @Override
437: public boolean hasRemaining() {
438: return rightPos < end;
439: }
440:
441: @Override
442: public String toString() {
443: return "(pool=" + pool.length + " pos=" + rightPos + " cap=" + end + ')';
444: }
445:
446: private void clearByteBufferCache() {
447: Arrays.fill(byteBufferCache, 0, byteBufferCacheSize, null);
448: byteBufferCacheSize = 0;
449: }
450:
451: } // END ByteBufferThreadLocalPool
452:
453: /**
454: * {@link HeapBuffer} implementation, which supports trimming. In other words it's possible to return unused
455: * {@link org.glassfish.grizzly.Buffer} space to pool.
456: */
457: private static final class TrimmableHeapBuffer extends HeapBuffer implements TrimAware {
458:
459: private HeapMemoryManager mm;
460:
461: private TrimmableHeapBuffer(final HeapMemoryManager mm, byte[] heap, int offset, int capacity) {
462: super(heap, offset, capacity);
463: this.mm = mm;
464: }
465:
466: @Override
467: public void trim() {
468: checkDispose();
469:
470: final int sizeToReturn = cap - pos;
471:
472: if (sizeToReturn > 0) {
473: final HeapBufferThreadLocalPool threadLocalCache = getHeapBufferThreadLocalPool();
474: if (threadLocalCache != null) {
475:
476: if (threadLocalCache.isLastAllocated(this)) {
477: flip();
478: cap = lim;
479: threadLocalCache.reduceLastAllocated(this);
480:
481: return;
482: } else if (threadLocalCache.wantReset(sizeToReturn)) {
483: flip();
484:
485: cap = lim;
486:
487: threadLocalCache.reset(heap, offset + cap, sizeToReturn);
488: return;
489: }
490: }
491: }
492:
493: super.trim();
494: }
495:
496: @Override
497: public void recycle() {
498: allowBufferDispose = false;
499:
500: ThreadCache.putToCache(CACHE_IDX, this);
501: }
502:
503: @Override
504: public void dispose() {
505: prepareDispose();
506: mm.release(this);
507: mm = null;
508:
509: byteBuffer = null;
510: heap = null;
511: pos = 0;
512: offset = 0;
513: lim = 0;
514: cap = 0;
515: order = ByteOrder.BIG_ENDIAN;
516: bigEndian = true;
517: recycle();
518: }
519:
520: @Override
521: protected HeapBuffer createHeapBuffer(final int offs, final int capacity) {
522: return mm.createTrimAwareBuffer(heap, offs + offset, capacity);
523: }
524:
525: void initialize(final HeapMemoryManager mm, final byte[] heap, final int offset, final int length) {
526:
527: this.mm = mm;
528: this.heap = heap;
529: this.offset = offset;
530: pos = 0;
531: cap = length;
532: lim = length;
533:
534: disposeStackTrace = null;
535: }
536: } // END TrimAwareWrapper
537:
538: private final static class RecyclableByteBufferWrapper extends ByteBufferWrapper implements Cacheable {
539:
540: private RecyclableByteBufferWrapper(final ByteBuffer underlyingByteBuffer) {
541: super(underlyingByteBuffer);
542: }
543:
544: @Override
545: public void recycle() {
546: allowBufferDispose = false;
547:
548: ThreadCache.putToCache(BBW_CACHE_IDX, this);
549: }
550:
551: @Override
552: public void dispose() {
553: super.dispose();
554: recycle();
555: }
556:
557: private void initialize(final ByteBuffer underlyingByteBuffer) {
558: visible = underlyingByteBuffer;
559: disposeStackTrace = null;
560: }
561:
562: }
563: }