1   
2   
3   
4   
5   
6   
7   
8   
9   
10  
11  
12  
13  
14  
15  
16  
17  package io.netty.buffer;
18  
19  import static io.netty.util.internal.ObjectUtil.checkPositiveOrZero;
20  
21  import io.netty.util.NettyRuntime;
22  import io.netty.util.concurrent.EventExecutor;
23  import io.netty.util.concurrent.FastThreadLocal;
24  import io.netty.util.concurrent.FastThreadLocalThread;
25  import io.netty.util.internal.PlatformDependent;
26  import io.netty.util.internal.StringUtil;
27  import io.netty.util.internal.SystemPropertyUtil;
28  import io.netty.util.internal.ThreadExecutorMap;
29  import io.netty.util.internal.logging.InternalLogger;
30  import io.netty.util.internal.logging.InternalLoggerFactory;
31  
32  import java.nio.ByteBuffer;
33  import java.util.ArrayList;
34  import java.util.Collections;
35  import java.util.List;
36  import java.util.concurrent.TimeUnit;
37  
38  public class PooledByteBufAllocator extends AbstractByteBufAllocator implements ByteBufAllocatorMetricProvider {
39  
40      private static final InternalLogger logger = InternalLoggerFactory.getInstance(PooledByteBufAllocator.class);
41      private static final int DEFAULT_NUM_HEAP_ARENA;
42      private static final int DEFAULT_NUM_DIRECT_ARENA;
43  
44      private static final int DEFAULT_PAGE_SIZE;
45      private static final int DEFAULT_MAX_ORDER; 
46      private static final int DEFAULT_SMALL_CACHE_SIZE;
47      private static final int DEFAULT_NORMAL_CACHE_SIZE;
48      static final int DEFAULT_MAX_CACHED_BUFFER_CAPACITY;
49      private static final int DEFAULT_CACHE_TRIM_INTERVAL;
50      private static final long DEFAULT_CACHE_TRIM_INTERVAL_MILLIS;
51      private static final boolean DEFAULT_USE_CACHE_FOR_ALL_THREADS;
52      private static final int DEFAULT_DIRECT_MEMORY_CACHE_ALIGNMENT;
53      static final int DEFAULT_MAX_CACHED_BYTEBUFFERS_PER_CHUNK;
54      private static final boolean DEFAULT_DISABLE_CACHE_FINALIZERS_FOR_FAST_THREAD_LOCAL_THREADS;
55  
56      private static final int MIN_PAGE_SIZE = 4096;
57      private static final int MAX_CHUNK_SIZE = (int) (((long) Integer.MAX_VALUE + 1) / 2);
58  
59      private static final int CACHE_NOT_USED = 0;
60  
61      private final Runnable trimTask = new Runnable() {
62          @Override
63          public void run() {
64              PooledByteBufAllocator.this.trimCurrentThreadCache();
65          }
66      };
67  
68      static {
69          int defaultAlignment = SystemPropertyUtil.getInt(
70                  "io.netty.allocator.directMemoryCacheAlignment", 0);
71          int defaultPageSize = SystemPropertyUtil.getInt("io.netty.allocator.pageSize", 8192);
72          Throwable pageSizeFallbackCause = null;
73          try {
74              validateAndCalculatePageShifts(defaultPageSize, defaultAlignment);
75          } catch (Throwable t) {
76              pageSizeFallbackCause = t;
77              defaultPageSize = 8192;
78              defaultAlignment = 0;
79          }
80          DEFAULT_PAGE_SIZE = defaultPageSize;
81          DEFAULT_DIRECT_MEMORY_CACHE_ALIGNMENT = defaultAlignment;
82  
83          int defaultMaxOrder = SystemPropertyUtil.getInt("io.netty.allocator.maxOrder", 9);
84          Throwable maxOrderFallbackCause = null;
85          try {
86              validateAndCalculateChunkSize(DEFAULT_PAGE_SIZE, defaultMaxOrder);
87          } catch (Throwable t) {
88              maxOrderFallbackCause = t;
89              defaultMaxOrder = 9;
90          }
91          DEFAULT_MAX_ORDER = defaultMaxOrder;
92  
93          
94          
95          final Runtime runtime = Runtime.getRuntime();
96  
97          
98  
99  
100 
101 
102 
103 
104         final int defaultMinNumArena = NettyRuntime.availableProcessors() * 2;
105         final int defaultChunkSize = DEFAULT_PAGE_SIZE << DEFAULT_MAX_ORDER;
106         DEFAULT_NUM_HEAP_ARENA = Math.max(0,
107                 SystemPropertyUtil.getInt(
108                         "io.netty.allocator.numHeapArenas",
109                         (int) Math.min(
110                                 defaultMinNumArena,
111                                 runtime.maxMemory() / defaultChunkSize / 2 / 3)));
112         DEFAULT_NUM_DIRECT_ARENA = Math.max(0,
113                 SystemPropertyUtil.getInt(
114                         "io.netty.allocator.numDirectArenas",
115                         (int) Math.min(
116                                 defaultMinNumArena,
117                                 PlatformDependent.maxDirectMemory() / defaultChunkSize / 2 / 3)));
118 
119         
120         DEFAULT_SMALL_CACHE_SIZE = SystemPropertyUtil.getInt("io.netty.allocator.smallCacheSize", 256);
121         DEFAULT_NORMAL_CACHE_SIZE = SystemPropertyUtil.getInt("io.netty.allocator.normalCacheSize", 64);
122 
123         
124         
125         DEFAULT_MAX_CACHED_BUFFER_CAPACITY = SystemPropertyUtil.getInt(
126                 "io.netty.allocator.maxCachedBufferCapacity", 32 * 1024);
127 
128         
129         DEFAULT_CACHE_TRIM_INTERVAL = SystemPropertyUtil.getInt(
130                 "io.netty.allocator.cacheTrimInterval", 8192);
131 
132         if (SystemPropertyUtil.contains("io.netty.allocation.cacheTrimIntervalMillis")) {
133             logger.warn("-Dio.netty.allocation.cacheTrimIntervalMillis is deprecated," +
134                     " use -Dio.netty.allocator.cacheTrimIntervalMillis");
135 
136             if (SystemPropertyUtil.contains("io.netty.allocator.cacheTrimIntervalMillis")) {
137                 
138                 DEFAULT_CACHE_TRIM_INTERVAL_MILLIS = SystemPropertyUtil.getLong(
139                         "io.netty.allocator.cacheTrimIntervalMillis", 0);
140             } else {
141                 DEFAULT_CACHE_TRIM_INTERVAL_MILLIS = SystemPropertyUtil.getLong(
142                         "io.netty.allocation.cacheTrimIntervalMillis", 0);
143             }
144         } else {
145             DEFAULT_CACHE_TRIM_INTERVAL_MILLIS = SystemPropertyUtil.getLong(
146                     "io.netty.allocator.cacheTrimIntervalMillis", 0);
147         }
148 
149         DEFAULT_USE_CACHE_FOR_ALL_THREADS = SystemPropertyUtil.getBoolean(
150                 "io.netty.allocator.useCacheForAllThreads", false);
151 
152         DEFAULT_DISABLE_CACHE_FINALIZERS_FOR_FAST_THREAD_LOCAL_THREADS = SystemPropertyUtil.getBoolean(
153                 "io.netty.allocator.disableCacheFinalizersForFastThreadLocalThreads", false);
154 
155         
156         
157         DEFAULT_MAX_CACHED_BYTEBUFFERS_PER_CHUNK = SystemPropertyUtil.getInt(
158                 "io.netty.allocator.maxCachedByteBuffersPerChunk", 1023);
159 
160         if (logger.isDebugEnabled()) {
161             logger.debug("-Dio.netty.allocator.numHeapArenas: {}", DEFAULT_NUM_HEAP_ARENA);
162             logger.debug("-Dio.netty.allocator.numDirectArenas: {}", DEFAULT_NUM_DIRECT_ARENA);
163             if (pageSizeFallbackCause == null) {
164                 logger.debug("-Dio.netty.allocator.pageSize: {}", DEFAULT_PAGE_SIZE);
165             } else {
166                 logger.debug("-Dio.netty.allocator.pageSize: {}", DEFAULT_PAGE_SIZE, pageSizeFallbackCause);
167             }
168             if (maxOrderFallbackCause == null) {
169                 logger.debug("-Dio.netty.allocator.maxOrder: {}", DEFAULT_MAX_ORDER);
170             } else {
171                 logger.debug("-Dio.netty.allocator.maxOrder: {}", DEFAULT_MAX_ORDER, maxOrderFallbackCause);
172             }
173             logger.debug("-Dio.netty.allocator.chunkSize: {}", DEFAULT_PAGE_SIZE << DEFAULT_MAX_ORDER);
174             logger.debug("-Dio.netty.allocator.smallCacheSize: {}", DEFAULT_SMALL_CACHE_SIZE);
175             logger.debug("-Dio.netty.allocator.normalCacheSize: {}", DEFAULT_NORMAL_CACHE_SIZE);
176             logger.debug("-Dio.netty.allocator.maxCachedBufferCapacity: {}", DEFAULT_MAX_CACHED_BUFFER_CAPACITY);
177             logger.debug("-Dio.netty.allocator.cacheTrimInterval: {}", DEFAULT_CACHE_TRIM_INTERVAL);
178             logger.debug("-Dio.netty.allocator.cacheTrimIntervalMillis: {}", DEFAULT_CACHE_TRIM_INTERVAL_MILLIS);
179             logger.debug("-Dio.netty.allocator.useCacheForAllThreads: {}", DEFAULT_USE_CACHE_FOR_ALL_THREADS);
180             logger.debug("-Dio.netty.allocator.maxCachedByteBuffersPerChunk: {}",
181                     DEFAULT_MAX_CACHED_BYTEBUFFERS_PER_CHUNK);
182             logger.debug("-Dio.netty.allocator.disableCacheFinalizersForFastThreadLocalThreads: {}",
183                          DEFAULT_DISABLE_CACHE_FINALIZERS_FOR_FAST_THREAD_LOCAL_THREADS);
184         }
185     }
186 
187     public static final PooledByteBufAllocator DEFAULT =
188             new PooledByteBufAllocator(!PlatformDependent.isExplicitNoPreferDirect());
189 
190     private final PoolArena<byte[]>[] heapArenas;
191     private final PoolArena<ByteBuffer>[] directArenas;
192     private final int smallCacheSize;
193     private final int normalCacheSize;
194     private final List<PoolArenaMetric> heapArenaMetrics;
195     private final List<PoolArenaMetric> directArenaMetrics;
196     private final PoolThreadLocalCache threadCache;
197     private final int chunkSize;
198     private final PooledByteBufAllocatorMetric metric;
199 
200     public PooledByteBufAllocator() {
201         this(false);
202     }
203 
204     @SuppressWarnings("deprecation")
205     public PooledByteBufAllocator(boolean preferDirect) {
206         this(preferDirect, DEFAULT_NUM_HEAP_ARENA, DEFAULT_NUM_DIRECT_ARENA, DEFAULT_PAGE_SIZE, DEFAULT_MAX_ORDER);
207     }
208 
209     @SuppressWarnings("deprecation")
210     public PooledByteBufAllocator(int nHeapArena, int nDirectArena, int pageSize, int maxOrder) {
211         this(false, nHeapArena, nDirectArena, pageSize, maxOrder);
212     }
213 
214     
215 
216 
217 
218     @Deprecated
219     public PooledByteBufAllocator(boolean preferDirect, int nHeapArena, int nDirectArena, int pageSize, int maxOrder) {
220         this(preferDirect, nHeapArena, nDirectArena, pageSize, maxOrder,
221              0, DEFAULT_SMALL_CACHE_SIZE, DEFAULT_NORMAL_CACHE_SIZE);
222     }
223 
224     
225 
226 
227 
228     @Deprecated
229     public PooledByteBufAllocator(boolean preferDirect, int nHeapArena, int nDirectArena, int pageSize, int maxOrder,
230                                   int tinyCacheSize, int smallCacheSize, int normalCacheSize) {
231         this(preferDirect, nHeapArena, nDirectArena, pageSize, maxOrder, smallCacheSize,
232              normalCacheSize, DEFAULT_USE_CACHE_FOR_ALL_THREADS, DEFAULT_DIRECT_MEMORY_CACHE_ALIGNMENT);
233     }
234 
235     
236 
237 
238 
239     @Deprecated
240     public PooledByteBufAllocator(boolean preferDirect, int nHeapArena,
241                                   int nDirectArena, int pageSize, int maxOrder, int tinyCacheSize,
242                                   int smallCacheSize, int normalCacheSize,
243                                   boolean useCacheForAllThreads) {
244         this(preferDirect, nHeapArena, nDirectArena, pageSize, maxOrder,
245              smallCacheSize, normalCacheSize,
246              useCacheForAllThreads);
247     }
248 
249     public PooledByteBufAllocator(boolean preferDirect, int nHeapArena,
250                                   int nDirectArena, int pageSize, int maxOrder,
251                                   int smallCacheSize, int normalCacheSize,
252                                   boolean useCacheForAllThreads) {
253         this(preferDirect, nHeapArena, nDirectArena, pageSize, maxOrder,
254              smallCacheSize, normalCacheSize,
255              useCacheForAllThreads, DEFAULT_DIRECT_MEMORY_CACHE_ALIGNMENT);
256     }
257 
258     
259 
260 
261 
262     @Deprecated
263     public PooledByteBufAllocator(boolean preferDirect, int nHeapArena, int nDirectArena, int pageSize, int maxOrder,
264                                   int tinyCacheSize, int smallCacheSize, int normalCacheSize,
265                                   boolean useCacheForAllThreads, int directMemoryCacheAlignment) {
266         this(preferDirect, nHeapArena, nDirectArena, pageSize, maxOrder,
267              smallCacheSize, normalCacheSize,
268              useCacheForAllThreads, directMemoryCacheAlignment);
269     }
270 
271     public PooledByteBufAllocator(boolean preferDirect, int nHeapArena, int nDirectArena, int pageSize, int maxOrder,
272                                   int smallCacheSize, int normalCacheSize,
273                                   boolean useCacheForAllThreads, int directMemoryCacheAlignment) {
274         super(preferDirect);
275         threadCache = new PoolThreadLocalCache(useCacheForAllThreads);
276         this.smallCacheSize = smallCacheSize;
277         this.normalCacheSize = normalCacheSize;
278 
279         if (directMemoryCacheAlignment != 0) {
280             if (!PlatformDependent.hasAlignDirectByteBuffer()) {
281                 throw new UnsupportedOperationException("Buffer alignment is not supported. " +
282                         "Either Unsafe or ByteBuffer.alignSlice() must be available.");
283             }
284 
285             
286             pageSize = (int) PlatformDependent.align(pageSize, directMemoryCacheAlignment);
287         }
288 
289         chunkSize = validateAndCalculateChunkSize(pageSize, maxOrder);
290 
291         checkPositiveOrZero(nHeapArena, "nHeapArena");
292         checkPositiveOrZero(nDirectArena, "nDirectArena");
293 
294         checkPositiveOrZero(directMemoryCacheAlignment, "directMemoryCacheAlignment");
295         if (directMemoryCacheAlignment > 0 && !isDirectMemoryCacheAlignmentSupported()) {
296             throw new IllegalArgumentException("directMemoryCacheAlignment is not supported");
297         }
298 
299         if ((directMemoryCacheAlignment & -directMemoryCacheAlignment) != directMemoryCacheAlignment) {
300             throw new IllegalArgumentException("directMemoryCacheAlignment: "
301                     + directMemoryCacheAlignment + " (expected: power of two)");
302         }
303 
304         int pageShifts = validateAndCalculatePageShifts(pageSize, directMemoryCacheAlignment);
305 
306         if (nHeapArena > 0) {
307             heapArenas = newArenaArray(nHeapArena);
308             List<PoolArenaMetric> metrics = new ArrayList<PoolArenaMetric>(heapArenas.length);
309             final SizeClasses sizeClasses = new SizeClasses(pageSize, pageShifts, chunkSize, 0);
310             for (int i = 0; i < heapArenas.length; i ++) {
311                 PoolArena.HeapArena arena = new PoolArena.HeapArena(this, sizeClasses);
312                 heapArenas[i] = arena;
313                 metrics.add(arena);
314             }
315             heapArenaMetrics = Collections.unmodifiableList(metrics);
316         } else {
317             heapArenas = null;
318             heapArenaMetrics = Collections.emptyList();
319         }
320 
321         if (nDirectArena > 0) {
322             directArenas = newArenaArray(nDirectArena);
323             List<PoolArenaMetric> metrics = new ArrayList<PoolArenaMetric>(directArenas.length);
324             final SizeClasses sizeClasses = new SizeClasses(pageSize, pageShifts, chunkSize,
325                     directMemoryCacheAlignment);
326             for (int i = 0; i < directArenas.length; i ++) {
327                 PoolArena.DirectArena arena = new PoolArena.DirectArena(this, sizeClasses);
328                 directArenas[i] = arena;
329                 metrics.add(arena);
330             }
331             directArenaMetrics = Collections.unmodifiableList(metrics);
332         } else {
333             directArenas = null;
334             directArenaMetrics = Collections.emptyList();
335         }
336         metric = new PooledByteBufAllocatorMetric(this);
337     }
338 
339     @SuppressWarnings("unchecked")
340     private static <T> PoolArena<T>[] newArenaArray(int size) {
341         return new PoolArena[size];
342     }
343 
344     private static int validateAndCalculatePageShifts(int pageSize, int alignment) {
345         if (pageSize < MIN_PAGE_SIZE) {
346             throw new IllegalArgumentException("pageSize: " + pageSize + " (expected: " + MIN_PAGE_SIZE + ')');
347         }
348 
349         if ((pageSize & pageSize - 1) != 0) {
350             throw new IllegalArgumentException("pageSize: " + pageSize + " (expected: power of 2)");
351         }
352 
353         if (pageSize < alignment) {
354             throw new IllegalArgumentException("Alignment cannot be greater than page size. " +
355                     "Alignment: " + alignment + ", page size: " + pageSize + '.');
356         }
357 
358         
359         return Integer.SIZE - 1 - Integer.numberOfLeadingZeros(pageSize);
360     }
361 
362     private static int validateAndCalculateChunkSize(int pageSize, int maxOrder) {
363         if (maxOrder > 14) {
364             throw new IllegalArgumentException("maxOrder: " + maxOrder + " (expected: 0-14)");
365         }
366 
367         
368         int chunkSize = pageSize;
369         for (int i = maxOrder; i > 0; i --) {
370             if (chunkSize > MAX_CHUNK_SIZE / 2) {
371                 throw new IllegalArgumentException(String.format(
372                         "pageSize (%d) << maxOrder (%d) must not exceed %d", pageSize, maxOrder, MAX_CHUNK_SIZE));
373             }
374             chunkSize <<= 1;
375         }
376         return chunkSize;
377     }
378 
379     @Override
380     protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
381         PoolThreadCache cache = threadCache.get();
382         PoolArena<byte[]> heapArena = cache.heapArena;
383 
384         final AbstractByteBuf buf;
385         if (heapArena != null) {
386             buf = heapArena.allocate(cache, initialCapacity, maxCapacity);
387         } else {
388             buf = PlatformDependent.hasUnsafe() ?
389                     new UnpooledUnsafeHeapByteBuf(this, initialCapacity, maxCapacity) :
390                     new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
391             onAllocateBuffer(buf, false, false);
392         }
393         return toLeakAwareBuffer(buf);
394     }
395 
396     @Override
397     protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
398         PoolThreadCache cache = threadCache.get();
399         PoolArena<ByteBuffer> directArena = cache.directArena;
400 
401         final AbstractByteBuf buf;
402         if (directArena != null) {
403             buf = directArena.allocate(cache, initialCapacity, maxCapacity);
404         } else {
405             buf = PlatformDependent.hasUnsafe() ?
406                     UnsafeByteBufUtil.newUnsafeDirectByteBuf(this, initialCapacity, maxCapacity, true) :
407                     new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity, true);
408             onAllocateBuffer(buf, false, false);
409         }
410         return toLeakAwareBuffer(buf);
411     }
412 
413     
414 
415 
416     public static int defaultNumHeapArena() {
417         return DEFAULT_NUM_HEAP_ARENA;
418     }
419 
420     
421 
422 
423     public static int defaultNumDirectArena() {
424         return DEFAULT_NUM_DIRECT_ARENA;
425     }
426 
427     
428 
429 
430     public static int defaultPageSize() {
431         return DEFAULT_PAGE_SIZE;
432     }
433 
434     
435 
436 
437     public static int defaultMaxOrder() {
438         return DEFAULT_MAX_ORDER;
439     }
440 
441     
442 
443 
444 
445     public static boolean defaultDisableCacheFinalizersForFastThreadLocalThreads() {
446         return DEFAULT_DISABLE_CACHE_FINALIZERS_FOR_FAST_THREAD_LOCAL_THREADS;
447     }
448 
449     
450 
451 
452     public static boolean defaultUseCacheForAllThreads() {
453         return DEFAULT_USE_CACHE_FOR_ALL_THREADS;
454     }
455 
456     
457 
458 
459     public static boolean defaultPreferDirect() {
460         return PlatformDependent.directBufferPreferred();
461     }
462 
463     
464 
465 
466 
467 
468     @Deprecated
469     public static int defaultTinyCacheSize() {
470         return 0;
471     }
472 
473     
474 
475 
476     public static int defaultSmallCacheSize() {
477         return DEFAULT_SMALL_CACHE_SIZE;
478     }
479 
480     
481 
482 
483     public static int defaultNormalCacheSize() {
484         return DEFAULT_NORMAL_CACHE_SIZE;
485     }
486 
487     
488 
489 
490     public static boolean isDirectMemoryCacheAlignmentSupported() {
491         return PlatformDependent.hasUnsafe();
492     }
493 
494     @Override
495     public boolean isDirectBufferPooled() {
496         return directArenas != null;
497     }
498 
499     
500 
501 
502 
503 
504     @Deprecated
505     public boolean hasThreadLocalCache() {
506         return threadCache.isSet();
507     }
508 
509     
510 
511 
512 
513     @Deprecated
514     public void freeThreadLocalCache() {
515         threadCache.remove();
516     }
517 
518     private final class PoolThreadLocalCache extends FastThreadLocal<PoolThreadCache> {
519         private final boolean useCacheForAllThreads;
520 
521         PoolThreadLocalCache(boolean useCacheForAllThreads) {
522             this.useCacheForAllThreads = useCacheForAllThreads;
523         }
524 
525         @Override
526         protected synchronized PoolThreadCache initialValue() {
527             final PoolArena<byte[]> heapArena = leastUsedArena(heapArenas);
528             final PoolArena<ByteBuffer> directArena = leastUsedArena(directArenas);
529 
530             final Thread current = Thread.currentThread();
531             final EventExecutor executor = ThreadExecutorMap.currentExecutor();
532 
533             if (useCacheForAllThreads ||
534                     
535                     FastThreadLocalThread.currentThreadHasFastThreadLocal() ||
536                     
537                     
538                     executor != null) {
539                 final PoolThreadCache cache = new PoolThreadCache(
540                         heapArena, directArena, smallCacheSize, normalCacheSize,
541                         DEFAULT_MAX_CACHED_BUFFER_CAPACITY, DEFAULT_CACHE_TRIM_INTERVAL, useCacheFinalizers());
542 
543                 if (DEFAULT_CACHE_TRIM_INTERVAL_MILLIS > 0) {
544                     if (executor != null) {
545                         executor.scheduleAtFixedRate(trimTask, DEFAULT_CACHE_TRIM_INTERVAL_MILLIS,
546                                 DEFAULT_CACHE_TRIM_INTERVAL_MILLIS, TimeUnit.MILLISECONDS);
547                     }
548                 }
549                 return cache;
550             }
551             
552             return new PoolThreadCache(heapArena, directArena, 0, 0, 0, 0, false);
553         }
554 
555         @Override
556         protected void onRemoval(PoolThreadCache threadCache) {
557             threadCache.free(false);
558         }
559 
560         private <T> PoolArena<T> leastUsedArena(PoolArena<T>[] arenas) {
561             if (arenas == null || arenas.length == 0) {
562                 return null;
563             }
564 
565             PoolArena<T> minArena = arenas[0];
566             
567             
568             if (minArena.numThreadCaches.get() == CACHE_NOT_USED) {
569                 return minArena;
570             }
571             for (int i = 1; i < arenas.length; i++) {
572                 PoolArena<T> arena = arenas[i];
573                 if (arena.numThreadCaches.get() < minArena.numThreadCaches.get()) {
574                     minArena = arena;
575                 }
576             }
577 
578             return minArena;
579         }
580     }
581 
582     private static boolean useCacheFinalizers() {
583         if (!defaultDisableCacheFinalizersForFastThreadLocalThreads()) {
584             return true;
585         }
586         return FastThreadLocalThread.currentThreadWillCleanupFastThreadLocals();
587     }
588 
589     @Override
590     public PooledByteBufAllocatorMetric metric() {
591         return metric;
592     }
593 
594     
595 
596 
597 
598 
599     @Deprecated
600     public int numHeapArenas() {
601         return heapArenaMetrics.size();
602     }
603 
604     
605 
606 
607 
608 
609     @Deprecated
610     public int numDirectArenas() {
611         return directArenaMetrics.size();
612     }
613 
614     
615 
616 
617 
618 
619     @Deprecated
620     public List<PoolArenaMetric> heapArenas() {
621         return heapArenaMetrics;
622     }
623 
624     
625 
626 
627 
628 
629     @Deprecated
630     public List<PoolArenaMetric> directArenas() {
631         return directArenaMetrics;
632     }
633 
634     
635 
636 
637 
638 
639     @Deprecated
640     public int numThreadLocalCaches() {
641         return Math.max(numThreadLocalCaches(heapArenas), numThreadLocalCaches(directArenas));
642     }
643 
644     private static int numThreadLocalCaches(PoolArena<?>[] arenas) {
645         if (arenas == null) {
646             return 0;
647         }
648 
649         int total = 0;
650         for (PoolArena<?> arena : arenas) {
651             total += arena.numThreadCaches.get();
652         }
653 
654         return total;
655     }
656 
657     
658 
659 
660 
661 
662     @Deprecated
663     public int tinyCacheSize() {
664         return 0;
665     }
666 
667     
668 
669 
670 
671 
672     @Deprecated
673     public int smallCacheSize() {
674         return smallCacheSize;
675     }
676 
677     
678 
679 
680 
681 
682     @Deprecated
683     public int normalCacheSize() {
684         return normalCacheSize;
685     }
686 
687     
688 
689 
690 
691 
692     @Deprecated
693     public final int chunkSize() {
694         return chunkSize;
695     }
696 
697     final long usedHeapMemory() {
698         return usedMemory(heapArenas);
699     }
700 
701     final long usedDirectMemory() {
702         return usedMemory(directArenas);
703     }
704 
705     private static long usedMemory(PoolArena<?>[] arenas) {
706         if (arenas == null) {
707             return -1;
708         }
709         long used = 0;
710         for (PoolArena<?> arena : arenas) {
711             used += arena.numActiveBytes();
712             if (used < 0) {
713                 return Long.MAX_VALUE;
714             }
715         }
716         return used;
717     }
718 
719     
720 
721 
722 
723 
724 
725     public final long pinnedHeapMemory() {
726         return pinnedMemory(heapArenas);
727     }
728 
729     
730 
731 
732 
733 
734 
735     public final long pinnedDirectMemory() {
736         return pinnedMemory(directArenas);
737     }
738 
739     private static long pinnedMemory(PoolArena<?>[] arenas) {
740         if (arenas == null) {
741             return -1;
742         }
743         long used = 0;
744         for (PoolArena<?> arena : arenas) {
745             used += arena.numPinnedBytes();
746             if (used < 0) {
747                 return Long.MAX_VALUE;
748             }
749         }
750         return used;
751     }
752 
753     final PoolThreadCache threadCache() {
754         PoolThreadCache cache =  threadCache.get();
755         assert cache != null;
756         return cache;
757     }
758 
759     
760 
761 
762 
763 
764 
765     public boolean trimCurrentThreadCache() {
766         PoolThreadCache cache = threadCache.getIfExists();
767         if (cache != null) {
768             cache.trim();
769             return true;
770         }
771         return false;
772     }
773 
774     
775 
776 
777 
778     public String dumpStats() {
779         int heapArenasLen = heapArenas == null ? 0 : heapArenas.length;
780         StringBuilder buf = new StringBuilder(512)
781                 .append(heapArenasLen)
782                 .append(" heap arena(s):")
783                 .append(StringUtil.NEWLINE);
784         if (heapArenasLen > 0) {
785             for (PoolArena<byte[]> a: heapArenas) {
786                 buf.append(a);
787             }
788         }
789 
790         int directArenasLen = directArenas == null ? 0 : directArenas.length;
791 
792         buf.append(directArenasLen)
793            .append(" direct arena(s):")
794            .append(StringUtil.NEWLINE);
795         if (directArenasLen > 0) {
796             for (PoolArena<ByteBuffer> a: directArenas) {
797                 buf.append(a);
798             }
799         }
800 
801         return buf.toString();
802     }
803 
804     static void onAllocateBuffer(AbstractByteBuf buf, boolean pooled, boolean threadLocal) {
805         if (PlatformDependent.isJfrEnabled() && AllocateBufferEvent.isEventEnabled()) {
806             AllocateBufferEvent event = new AllocateBufferEvent();
807             if (event.shouldCommit()) {
808                 event.fill(buf, PooledByteBufAllocator.class);
809                 event.chunkPooled = pooled;
810                 event.chunkThreadLocal = threadLocal;
811                 event.commit();
812             }
813         }
814     }
815 
816     static void onDeallocateBuffer(AbstractByteBuf buf) {
817         if (PlatformDependent.isJfrEnabled() && FreeBufferEvent.isEventEnabled()) {
818             FreeBufferEvent event = new FreeBufferEvent();
819             if (event.shouldCommit()) {
820                 event.fill(buf, PooledByteBufAllocator.class);
821                 event.commit();
822             }
823         }
824     }
825 
826     static void onReallocateBuffer(AbstractByteBuf buf, int newCapacity) {
827         if (PlatformDependent.isJfrEnabled() && ReallocateBufferEvent.isEventEnabled()) {
828             ReallocateBufferEvent event = new ReallocateBufferEvent();
829             if (event.shouldCommit()) {
830                 event.fill(buf, PooledByteBufAllocator.class);
831                 event.newCapacity = newCapacity;
832                 event.commit();
833             }
834         }
835     }
836 
837     static void onAllocateChunk(ChunkInfo chunk, boolean pooled) {
838         if (PlatformDependent.isJfrEnabled() && AllocateChunkEvent.isEventEnabled()) {
839             AllocateChunkEvent event = new AllocateChunkEvent();
840             if (event.shouldCommit()) {
841                 event.fill(chunk, PooledByteBufAllocator.class);
842                 event.pooled = pooled;
843                 event.threadLocal = false; 
844                 event.commit();
845             }
846         }
847     }
848 
849     static void onDeallocateChunk(ChunkInfo chunk, boolean pooled) {
850         if (PlatformDependent.isJfrEnabled() && FreeChunkEvent.isEventEnabled()) {
851             FreeChunkEvent event = new FreeChunkEvent();
852             if (event.shouldCommit()) {
853                 event.fill(chunk, PooledByteBufAllocator.class);
854                 event.pooled = pooled;
855                 event.commit();
856             }
857         }
858     }
859 }