// Copyright (c) Microsoft. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Runtime.InteropServices; namespace System.Buffers { /// /// Slab tracking object used by the byte buffer memory pool. A slab is a large allocation which is divided into smaller blocks. The /// individual blocks are then treated as independent array segments. /// internal class MemoryPoolSlab : IDisposable { /// /// This handle pins the managed array in memory until the slab is disposed. This prevents it from being /// relocated and enables any subsections of the array to be used as native memory pointers to P/Invoked API calls. /// private GCHandle _gcHandle; private bool _isDisposed; public MemoryPoolSlab(byte[] data) { Array = data; _gcHandle = GCHandle.Alloc(data, GCHandleType.Pinned); NativePointer = _gcHandle.AddrOfPinnedObject(); } /// /// True as long as the blocks from this slab are to be considered returnable to the pool. In order to shrink the /// memory pool size an entire slab must be removed. That is done by (1) setting IsActive to false and removing the /// slab from the pool's _slabs collection, (2) as each block currently in use is Return()ed to the pool it will /// be allowed to be garbage collected rather than re-pooled, and (3) when all block tracking objects are garbage /// collected and the slab is no longer references the slab will be garbage collected and the memory unpinned will /// be unpinned by the slab's Dispose. /// public bool IsActive => !_isDisposed; public IntPtr NativePointer { get; private set; } public byte[] Array { get; private set; } public static MemoryPoolSlab Create(int length) { // allocate and pin requested memory length var array = new byte[length]; // allocate and return slab tracking object return new MemoryPoolSlab(array); } protected void Dispose(bool disposing) { if (_isDisposed) { return; } _isDisposed = true; Array = null; NativePointer = IntPtr.Zero;; if (_gcHandle.IsAllocated) { _gcHandle.Free(); } } ~MemoryPoolSlab() { Dispose(false); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } } }