PooledByteBufAllocator

来源:互联网 发布:vscode extjs 编辑:程序博客网 时间:2024/06/06 06:32
/* * Copyright 2012 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * *   http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */package io.netty.buffer;import io.netty.util.concurrent.FastThreadLocal;import io.netty.util.internal.PlatformDependent;import io.netty.util.internal.SystemPropertyUtil;import io.netty.util.internal.logging.InternalLogger;import io.netty.util.internal.logging.InternalLoggerFactory;import java.nio.ByteBuffer;import java.util.concurrent.atomic.AtomicInteger;public class PooledByteBufAllocator extends AbstractByteBufAllocator {    private static final InternalLogger logger = InternalLoggerFactory.getInstance(PooledByteBufAllocator.class);    private static final int DEFAULT_NUM_HEAP_ARENA;    private static final int DEFAULT_NUM_DIRECT_ARENA;    private static final int DEFAULT_PAGE_SIZE;    private static final int DEFAULT_MAX_ORDER; // 8192 << 11 = 16 MiB per chunk    private static final int DEFAULT_TINY_CACHE_SIZE;    private static final int DEFAULT_SMALL_CACHE_SIZE;    private static final int DEFAULT_NORMAL_CACHE_SIZE;    private static final int DEFAULT_MAX_CACHED_BUFFER_CAPACITY;    private static final int DEFAULT_CACHE_TRIM_INTERVAL;    private static final int MIN_PAGE_SIZE = 4096;    private static final int MAX_CHUNK_SIZE = (int) (((long) Integer.MAX_VALUE + 1) / 2);    static {        int defaultPageSize = SystemPropertyUtil.getInt("io.netty.allocator.pageSize", 8192);        Throwable pageSizeFallbackCause = null;        try {            validateAndCalculatePageShifts(defaultPageSize);        } catch (Throwable t) {            pageSizeFallbackCause = t;            defaultPageSize = 8192;        }        DEFAULT_PAGE_SIZE = defaultPageSize;        int defaultMaxOrder = SystemPropertyUtil.getInt("io.netty.allocator.maxOrder", 11);        Throwable maxOrderFallbackCause = null;        try {            validateAndCalculateChunkSize(DEFAULT_PAGE_SIZE, defaultMaxOrder);        } catch (Throwable t) {            maxOrderFallbackCause = t;            defaultMaxOrder = 11;        }        DEFAULT_MAX_ORDER = defaultMaxOrder;        // Determine reasonable default for nHeapArena and nDirectArena.        // Assuming each arena has 3 chunks, the pool should not consume more than 50% of max memory.        final Runtime runtime = Runtime.getRuntime();        final int defaultChunkSize = DEFAULT_PAGE_SIZE << DEFAULT_MAX_ORDER;        DEFAULT_NUM_HEAP_ARENA = Math.max(0,                SystemPropertyUtil.getInt(                        "io.netty.allocator.numHeapArenas",                        (int) Math.min(                                runtime.availableProcessors(),                                Runtime.getRuntime().maxMemory() / defaultChunkSize / 2 / 3)));        DEFAULT_NUM_DIRECT_ARENA = Math.max(0,                SystemPropertyUtil.getInt(                        "io.netty.allocator.numDirectArenas",                        (int) Math.min(                                runtime.availableProcessors(),                                PlatformDependent.maxDirectMemory() / defaultChunkSize / 2 / 3)));        // cache sizes        DEFAULT_TINY_CACHE_SIZE = SystemPropertyUtil.getInt("io.netty.allocator.tinyCacheSize", 512);        DEFAULT_SMALL_CACHE_SIZE = SystemPropertyUtil.getInt("io.netty.allocator.smallCacheSize", 256);        DEFAULT_NORMAL_CACHE_SIZE = SystemPropertyUtil.getInt("io.netty.allocator.normalCacheSize", 64);        // 32 kb is the default maximum capacity of the cached buffer. Similar to what is explained in        // 'Scalable memory allocation using jemalloc'        DEFAULT_MAX_CACHED_BUFFER_CAPACITY = SystemPropertyUtil.getInt(                "io.netty.allocator.maxCachedBufferCapacity", 32 * 1024);        // the number of threshold of allocations when cached entries will be freed up if not frequently used        DEFAULT_CACHE_TRIM_INTERVAL = SystemPropertyUtil.getInt(                "io.netty.allocator.cacheTrimInterval", 8192);        if (logger.isDebugEnabled()) {            logger.debug("-Dio.netty.allocator.numHeapArenas: {}", DEFAULT_NUM_HEAP_ARENA);            logger.debug("-Dio.netty.allocator.numDirectArenas: {}", DEFAULT_NUM_DIRECT_ARENA);            if (pageSizeFallbackCause == null) {                logger.debug("-Dio.netty.allocator.pageSize: {}", DEFAULT_PAGE_SIZE);            } else {                logger.debug("-Dio.netty.allocator.pageSize: {}", DEFAULT_PAGE_SIZE, pageSizeFallbackCause);            }            if (maxOrderFallbackCause == null) {                logger.debug("-Dio.netty.allocator.maxOrder: {}", DEFAULT_MAX_ORDER);            } else {                logger.debug("-Dio.netty.allocator.maxOrder: {}", DEFAULT_MAX_ORDER, maxOrderFallbackCause);            }            logger.debug("-Dio.netty.allocator.chunkSize: {}", DEFAULT_PAGE_SIZE << DEFAULT_MAX_ORDER);            logger.debug("-Dio.netty.allocator.tinyCacheSize: {}", DEFAULT_TINY_CACHE_SIZE);            logger.debug("-Dio.netty.allocator.smallCacheSize: {}", DEFAULT_SMALL_CACHE_SIZE);            logger.debug("-Dio.netty.allocator.normalCacheSize: {}", DEFAULT_NORMAL_CACHE_SIZE);            logger.debug("-Dio.netty.allocator.maxCachedBufferCapacity: {}", DEFAULT_MAX_CACHED_BUFFER_CAPACITY);            logger.debug("-Dio.netty.allocator.cacheTrimInterval: {}", DEFAULT_CACHE_TRIM_INTERVAL);        }    }    public static final PooledByteBufAllocator DEFAULT =            new PooledByteBufAllocator(PlatformDependent.directBufferPreferred());    private final PoolArena<byte[]>[] heapArenas;    private final PoolArena<ByteBuffer>[] directArenas;    private final int tinyCacheSize;    private final int smallCacheSize;    private final int normalCacheSize;    final PoolThreadLocalCache threadCache;    public PooledByteBufAllocator() {        this(false);    }    public PooledByteBufAllocator(boolean preferDirect) {        this(preferDirect, DEFAULT_NUM_HEAP_ARENA, DEFAULT_NUM_DIRECT_ARENA, DEFAULT_PAGE_SIZE, DEFAULT_MAX_ORDER);    }    public PooledByteBufAllocator(int nHeapArena, int nDirectArena, int pageSize, int maxOrder) {        this(false, nHeapArena, nDirectArena, pageSize, maxOrder);    }    public PooledByteBufAllocator(boolean preferDirect, int nHeapArena, int nDirectArena, int pageSize, int maxOrder) {        this(preferDirect, nHeapArena, nDirectArena, pageSize, maxOrder,                DEFAULT_TINY_CACHE_SIZE, DEFAULT_SMALL_CACHE_SIZE, DEFAULT_NORMAL_CACHE_SIZE);    }    public PooledByteBufAllocator(boolean preferDirect, int nHeapArena, int nDirectArena, int pageSize, int maxOrder,                                  int tinyCacheSize, int smallCacheSize, int normalCacheSize) {        super(preferDirect);        threadCache = new PoolThreadLocalCache();        this.tinyCacheSize = tinyCacheSize;        this.smallCacheSize = smallCacheSize;        this.normalCacheSize = normalCacheSize;        final int chunkSize = validateAndCalculateChunkSize(pageSize, maxOrder);        if (nHeapArena < 0) {            throw new IllegalArgumentException("nHeapArena: " + nHeapArena + " (expected: >= 0)");        }        if (nDirectArena < 0) {            throw new IllegalArgumentException("nDirectArea: " + nDirectArena + " (expected: >= 0)");        }        int pageShifts = validateAndCalculatePageShifts(pageSize);        if (nHeapArena > 0) {            heapArenas = newArenaArray(nHeapArena);            for (int i = 0; i < heapArenas.length; i ++) {                heapArenas[i] = new PoolArena.HeapArena(this, pageSize, maxOrder, pageShifts, chunkSize);            }        } else {            heapArenas = null;        }        if (nDirectArena > 0) {            directArenas = newArenaArray(nDirectArena);            for (int i = 0; i < directArenas.length; i ++) {                directArenas[i] = new PoolArena.DirectArena(this, pageSize, maxOrder, pageShifts, chunkSize);            }        } else {            directArenas = null;        }    }    @Deprecated    @SuppressWarnings("UnusedParameters")    public PooledByteBufAllocator(boolean preferDirect, int nHeapArena, int nDirectArena, int pageSize, int maxOrder,                                  int tinyCacheSize, int smallCacheSize, int normalCacheSize,                                  long cacheThreadAliveCheckInterval) {        this(preferDirect, nHeapArena, nDirectArena, pageSize, maxOrder,                tinyCacheSize, smallCacheSize, normalCacheSize);    }    @SuppressWarnings("unchecked")    private static <T> PoolArena<T>[] newArenaArray(int size) {        return new PoolArena[size];    }    private static int validateAndCalculatePageShifts(int pageSize) {        if (pageSize < MIN_PAGE_SIZE) {            throw new IllegalArgumentException("pageSize: " + pageSize + " (expected: " + MIN_PAGE_SIZE + "+)");        }        if ((pageSize & pageSize - 1) != 0) {            throw new IllegalArgumentException("pageSize: " + pageSize + " (expected: power of 2)");        }        // Logarithm base 2. At this point we know that pageSize is a power of two.        return Integer.SIZE - 1 - Integer.numberOfLeadingZeros(pageSize);    }    private static int validateAndCalculateChunkSize(int pageSize, int maxOrder) {        if (maxOrder > 14) {            throw new IllegalArgumentException("maxOrder: " + maxOrder + " (expected: 0-14)");        }        // Ensure the resulting chunkSize does not overflow.        int chunkSize = pageSize;        for (int i = maxOrder; i > 0; i --) {            if (chunkSize > MAX_CHUNK_SIZE / 2) {                throw new IllegalArgumentException(String.format(                        "pageSize (%d) << maxOrder (%d) must not exceed %d", pageSize, maxOrder, MAX_CHUNK_SIZE));            }            chunkSize <<= 1;        }        return chunkSize;    }    @Override    protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {        PoolThreadCache cache = threadCache.get();        PoolArena<byte[]> heapArena = cache.heapArena;        ByteBuf buf;        if (heapArena != null) {            buf = heapArena.allocate(cache, initialCapacity, maxCapacity);        } else {            buf = new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);        }        return toLeakAwareBuffer(buf);    }    @Override    protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {        PoolThreadCache cache = threadCache.get();        PoolArena<ByteBuffer> directArena = cache.directArena;        ByteBuf buf;        if (directArena != null) {            buf = directArena.allocate(cache, initialCapacity, maxCapacity);        } else {            if (PlatformDependent.hasUnsafe()) {                buf = new UnpooledUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);            } else {                buf = new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);            }        }        return toLeakAwareBuffer(buf);    }    @Override    public boolean isDirectBufferPooled() {        return directArenas != null;    }    /**     * Returns {@code true} if the calling {@link Thread} has a {@link ThreadLocal} cache for the allocated     * buffers.     */    @Deprecated    public boolean hasThreadLocalCache() {        return threadCache.isSet();    }    /**     * Free all cached buffers for the calling {@link Thread}.     */    @Deprecated    public void freeThreadLocalCache() {        threadCache.remove();    }    final class PoolThreadLocalCache extends FastThreadLocal<PoolThreadCache> {        private final AtomicInteger index = new AtomicInteger();        @Override        protected PoolThreadCache initialValue() {            final int idx = index.getAndIncrement();            final PoolArena<byte[]> heapArena;            final PoolArena<ByteBuffer> directArena;            if (heapArenas != null) {                heapArena = heapArenas[Math.abs(idx % heapArenas.length)];            } else {                heapArena = null;            }            if (directArenas != null) {                directArena = directArenas[Math.abs(idx % directArenas.length)];            } else {                directArena = null;            }            return new PoolThreadCache(                    heapArena, directArena, tinyCacheSize, smallCacheSize, normalCacheSize,                    DEFAULT_MAX_CACHED_BUFFER_CAPACITY, DEFAULT_CACHE_TRIM_INTERVAL);        }        @Override        protected void onRemoval(PoolThreadCache value) {            value.free();        }    }//    Too noisy at the moment.////    public String toString() {//        StringBuilder buf = new StringBuilder();//        buf.append(heapArenas.length);//        buf.append(" heap arena(s):");//        buf.append(StringUtil.NEWLINE);//        for (PoolArena<byte[]> a: heapArenas) {//            buf.append(a);//        }//        buf.append(directArenas.length);//        buf.append(" direct arena(s):");//        buf.append(StringUtil.NEWLINE);//        for (PoolArena<ByteBuffer> a: directArenas) {//            buf.append(a);//        }//        return buf.toString();//    }}

0 0
原创粉丝点击