diff --git a/src/Shared/Buffers.MemoryPool/MemoryPoolBlock.cs b/src/Shared/Buffers.MemoryPool/MemoryPoolBlock.cs
index 0efe3dbef290..d829983c91d9 100644
--- a/src/Shared/Buffers.MemoryPool/MemoryPoolBlock.cs
+++ b/src/Shared/Buffers.MemoryPool/MemoryPoolBlock.cs
@@ -6,26 +6,17 @@
namespace System.Buffers
{
///
- /// Block 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.
+ /// Wraps an array allocated in the pinned object heap in a reusable block of managed memory
///
internal sealed class MemoryPoolBlock : IMemoryOwner
{
- private readonly int _offset;
- private readonly int _length;
-
- ///
- /// This object cannot be instantiated outside of the static Create method
- ///
- internal MemoryPoolBlock(SlabMemoryPool pool, MemoryPoolSlab slab, int offset, int length)
+ internal MemoryPoolBlock(SlabMemoryPool pool, int length)
{
- _offset = offset;
- _length = length;
-
Pool = pool;
- Slab = slab;
- Memory = MemoryMarshal.CreateFromPinnedArray(slab.PinnedArray, _offset, _length);
+ var pinnedArray = GC.AllocateUninitializedArray(length, pinned: true);
+
+ Memory = MemoryMarshal.CreateFromPinnedArray(pinnedArray, 0, pinnedArray.Length);
}
///
@@ -33,25 +24,11 @@ internal MemoryPoolBlock(SlabMemoryPool pool, MemoryPoolSlab slab, int offset, i
///
public SlabMemoryPool Pool { get; }
- ///
- /// Back-reference to the slab from which this block was taken, or null if it is one-time-use memory.
- ///
- public MemoryPoolSlab Slab { get; }
-
public Memory Memory { get; }
- ~MemoryPoolBlock()
- {
- Pool.RefreshBlock(Slab, _offset, _length);
- }
-
public void Dispose()
{
Pool.Return(this);
}
-
- public void Lease()
- {
- }
}
}
diff --git a/src/Shared/Buffers.MemoryPool/MemoryPoolSlab.cs b/src/Shared/Buffers.MemoryPool/MemoryPoolSlab.cs
deleted file mode 100644
index 6907ca99c449..000000000000
--- a/src/Shared/Buffers.MemoryPool/MemoryPoolSlab.cs
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) Microsoft. All rights reserved.
-// Licensed under the MIT license. See LICENSE file in the project root for full license information.
-
-#nullable enable
-
-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
- {
- private MemoryPoolSlab(byte[] pinnedData)
- {
- PinnedArray = pinnedData;
- }
-
- ///
- /// 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
- ///
- public bool IsActive => PinnedArray != null;
-
- public byte[]? PinnedArray { get; private set; }
-
- public static MemoryPoolSlab Create(int length)
- {
- // allocate requested memory length from the pinned memory heap
- var pinnedArray = GC.AllocateUninitializedArray(length, pinned: true);
-
- // allocate and return slab tracking object
- return new MemoryPoolSlab(pinnedArray);
- }
-
- public void Dispose()
- {
- PinnedArray = null;
- }
- }
-}
diff --git a/src/Shared/Buffers.MemoryPool/SlabMemoryPool.cs b/src/Shared/Buffers.MemoryPool/SlabMemoryPool.cs
index 6b01c0f9b220..4e766904bb3d 100644
--- a/src/Shared/Buffers.MemoryPool/SlabMemoryPool.cs
+++ b/src/Shared/Buffers.MemoryPool/SlabMemoryPool.cs
@@ -2,9 +2,6 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.Concurrent;
-using System.Diagnostics;
-using System.Runtime.InteropServices;
-using System.Threading;
#nullable enable
@@ -20,13 +17,6 @@ internal sealed class SlabMemoryPool : MemoryPool
///
private const int _blockSize = 4096;
- ///
- /// Allocating 32 contiguous blocks per slab makes the slab size 128k. This is larger than the 85k size which will place the memory
- /// in the large object heap. This means the GC will not try to relocate this array, so the fact it remains pinned does not negatively
- /// affect memory management's compactification.
- ///
- private const int _blockCount = 32;
-
///
/// Max allocation block size for pooled blocks,
/// larger values can be leased but they will be disposed after use rather than returned to the pool.
@@ -38,30 +28,17 @@ internal sealed class SlabMemoryPool : MemoryPool
///
public static int BlockSize => _blockSize;
- ///
- /// 4096 * 32 gives you a slabLength of 128k contiguous bytes allocated per slab
- ///
- private static readonly int _slabLength = _blockSize * _blockCount;
-
///
/// Thread-safe collection of blocks which are currently in the pool. A slab will pre-allocate all of the block tracking objects
/// and add them to this collection. When memory is requested it is taken from here first, and when it is returned it is re-added.
///
private readonly ConcurrentQueue _blocks = new ConcurrentQueue();
- ///
- /// Thread-safe collection of slabs which have been allocated by this pool. As long as a slab is in this collection and slab.IsActive,
- /// the blocks will be added to _blocks when returned.
- ///
- private readonly ConcurrentStack _slabs = new ConcurrentStack();
-
///
/// This is part of implementing the IDisposable pattern.
///
private bool _isDisposed; // To detect redundant calls
- private int _totalAllocatedBlocks;
-
private readonly object _disposeSync = new object();
///
@@ -76,16 +53,6 @@ public override IMemoryOwner Rent(int size = AnySize)
MemoryPoolThrowHelper.ThrowArgumentOutOfRangeException_BufferRequestTooLarge(_blockSize);
}
- var block = Lease();
- return block;
- }
-
- ///
- /// Called to take a block from the pool.
- ///
- /// The block that is reserved for the called. It must be passed to Return when it is no longer being used.
- private MemoryPoolBlock Lease()
- {
if (_isDisposed)
{
MemoryPoolThrowHelper.ThrowObjectDisposedException(MemoryPoolThrowHelper.ExceptionArgument.MemoryPool);
@@ -94,53 +61,9 @@ private MemoryPoolBlock Lease()
if (_blocks.TryDequeue(out var block))
{
// block successfully taken from the stack - return it
-
- block.Lease();
return block;
}
- // no blocks available - grow the pool
- block = AllocateSlab();
- block.Lease();
- return block;
- }
-
- ///
- /// 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.
- ///
- private MemoryPoolBlock AllocateSlab()
- {
- var slab = MemoryPoolSlab.Create(_slabLength);
- _slabs.Push(slab);
-
- // Get the address for alignment
- IntPtr basePtr = Marshal.UnsafeAddrOfPinnedArrayElement(slab.PinnedArray!, 0);
- // Page align the blocks
- var offset = (int)((((ulong)basePtr + (uint)_blockSize - 1) & ~((uint)_blockSize - 1)) - (ulong)basePtr);
- // Ensure page aligned
- Debug.Assert(((ulong)basePtr + (uint)offset) % _blockSize == 0);
-
- var blockCount = (_slabLength - offset) / _blockSize;
- Interlocked.Add(ref _totalAllocatedBlocks, blockCount);
-
- MemoryPoolBlock? block = null;
-
- for (int i = 0; i < blockCount; i++)
- {
- block = new MemoryPoolBlock(this, slab, offset, _blockSize);
-
- if (i != blockCount - 1) // last block
- {
-#if BLOCK_LEASE_TRACKING
- block.IsLeased = true;
-#endif
- Return(block);
- }
-
- offset += _blockSize;
- }
-
- return block!;
+ return new MemoryPoolBlock(this, BlockSize);
}
///
@@ -163,25 +86,6 @@ internal void Return(MemoryPoolBlock block)
{
_blocks.Enqueue(block);
}
- else
- {
- GC.SuppressFinalize(block);
- }
- }
-
- // This method can ONLY be called from the finalizer of MemoryPoolBlock
- internal void RefreshBlock(MemoryPoolSlab slab, int offset, int length)
- {
- lock (_disposeSync)
- {
- if (!_isDisposed && slab != null && slab.IsActive)
- {
- // Need to make a new object because this one is being finalized
- // Note, this must be called within the _disposeSync lock because the block
- // could be disposed at the same time as the finalizer.
- Return(new MemoryPoolBlock(this, slab, offset, length));
- }
- }
}
protected override void Dispose(bool disposing)
@@ -197,17 +101,11 @@ protected override void Dispose(bool disposing)
if (disposing)
{
- while (_slabs.TryPop(out var slab))
+ // Discard blocks in pool
+ while (_blocks.TryDequeue(out _))
{
- // dispose managed state (managed objects).
- slab.Dispose();
- }
- }
- // Discard blocks in pool
- while (_blocks.TryDequeue(out var block))
- {
- GC.SuppressFinalize(block);
+ }
}
}
}