/** * @param maxCacheableBlockSize Max size of cached blocks including alignment padding, must be a power of 2 * @param maxCachedBlocks Max number of blocks of each size to store */ public CachingOffHeapBlockAllocator( long maxCacheableBlockSize, int maxCachedBlocks ) { requirePositive( maxCachedBlocks ); this.maxCacheableBlockSize = requirePowerOfTwo( maxCacheableBlockSize ); final int numOfCaches = log2floor( maxCacheableBlockSize ) + 1; //noinspection unchecked this.caches = new BlockingQueue[numOfCaches]; for ( int i = 0; i < caches.length; i++ ) { caches[i] = new ArrayBlockingQueue<>( maxCachedBlocks ); } }
@Override public void free( MemoryBlock block, MemoryAllocationTracker tracker ) { if ( released || !isCacheable( block.size ) ) { doFree( block, tracker ); return; } final BlockingQueue<MemoryBlock> cache = caches[log2floor( block.size )]; if ( !cache.offer( block ) ) { doFree( block, tracker ); return; } // it is possible that allocator is released just before we put the block into queue; // in such case case we need to free memory right away, since release() will never be called again if ( released && cache.remove( block ) ) { doFree( block, tracker ); return; } tracker.deallocated( block.unalignedSize ); }
@Override public MemoryBlock allocate( long size, MemoryAllocationTracker tracker ) { requirePositive( size ); checkState( !released, "Allocator is already released" ); if ( !isCacheable( size ) ) { return allocateNew( size, tracker ); } final BlockingQueue<MemoryBlock> cache = caches[log2floor( size )]; MemoryBlock block = cache.poll(); if ( block == null ) { block = allocateNew( size, tracker ); } else { tracker.allocated( block.unalignedSize ); } return block; }
/** * @param maxCacheableBlockSize Max size of cached blocks including alignment padding, must be a power of 2 * @param maxCachedBlocks Max number of blocks of each size to store */ public CachingOffHeapBlockAllocator( long maxCacheableBlockSize, int maxCachedBlocks ) { requirePositive( maxCachedBlocks ); this.maxCacheableBlockSize = requirePowerOfTwo( maxCacheableBlockSize ); final int numOfCaches = log2floor( maxCacheableBlockSize ) + 1; //noinspection unchecked this.caches = new BlockingQueue[numOfCaches]; for ( int i = 0; i < caches.length; i++ ) { caches[i] = new ArrayBlockingQueue<>( maxCachedBlocks ); } }
@Override public void free( MemoryBlock block, MemoryAllocationTracker tracker ) { if ( released || !isCacheable( block.size ) ) { doFree( block, tracker ); return; } final BlockingQueue<MemoryBlock> cache = caches[log2floor( block.size )]; if ( !cache.offer( block ) ) { doFree( block, tracker ); return; } // it is possible that allocator is released just before we put the block into queue; // in such case case we need to free memory right away, since release() will never be called again if ( released && cache.remove( block ) ) { doFree( block, tracker ); return; } tracker.deallocated( block.unalignedSize ); }
@Override public MemoryBlock allocate( long size, MemoryAllocationTracker tracker ) { requirePositive( size ); checkState( !released, "Allocator is already released" ); if ( !isCacheable( size ) ) { return allocateNew( size, tracker ); } final BlockingQueue<MemoryBlock> cache = caches[log2floor( size )]; MemoryBlock block = cache.poll(); if ( block == null ) { block = allocateNew( size, tracker ); } else { tracker.allocated( block.unalignedSize ); } return block; }