/// <summary> /// Internal method called when a block is requested and the pool is empty. It allocates one additional slab, creates all of the /// block tracking objects, and adds them all to the pool. /// </summary> private MemoryPoolBlock AllocateSlab() { var slab = MemoryPoolSlab.Create(_slabLength); _slabs.Push(slab); var basePtr = slab.ArrayPtr; var firstOffset = (int)((_blockStride - 1) - ((ulong)(basePtr + _blockStride - 1) % _blockStride)); var poolAllocationLength = _slabLength - _blockStride; var offset = firstOffset; for (; offset + _blockLength < poolAllocationLength; offset += _blockStride) { var block = MemoryPoolBlock.Create( new ArraySegment <byte>(slab.Array, offset, _blockLength), basePtr, this, slab); Return(block); } // return last block rather than adding to pool var newBlock = MemoryPoolBlock.Create( new ArraySegment <byte>(slab.Array, offset, _blockLength), basePtr, this, slab); return(newBlock); }
private bool _disposedValue = false; // To detect redundant calls /// <summary> /// Called to take a block from the pool. /// </summary> /// <param name="minimumSize">The block returned must be at least this size. It may be larger than this minimum size, and if so, /// the caller may write to the block's entire size rather than being limited to the minumumSize requested.</param> /// <returns>The block that is reserved for the called. It must be passed to Return when it is no longer being used.</returns> public MemoryPoolBlock Lease(int minimumSize = MaxPooledBlockLength) { if (minimumSize > _blockLength) { // The requested minimumSize is actually larger then the usable memory of a single block. // Because this is the degenerate case, a one-time-use byte[] array and tracking object are allocated. // When this block tracking object is returned it is not added to the pool - instead it will be // allowed to be garbage collected normally. return(MemoryPoolBlock.Create( new ArraySegment <byte>(new byte[minimumSize]), dataPtr: IntPtr.Zero, pool: this, slab: null)); } MemoryPoolBlock block; if (_blocks.TryDequeue(out block)) { // block successfully taken from the stack - return it return(block); } // no blocks available - grow the pool return(AllocateSlab()); }