Use Pinned Object Heap for MemoryPool (#21614)
This commit is contained in:
parent
b062d1bbc3
commit
a410ed4601
|
|
@ -25,7 +25,7 @@ namespace System.Buffers
|
||||||
Pool = pool;
|
Pool = pool;
|
||||||
Slab = slab;
|
Slab = slab;
|
||||||
|
|
||||||
Memory = MemoryMarshal.CreateFromPinnedArray(slab.Array, _offset, _length);
|
Memory = MemoryMarshal.CreateFromPinnedArray(slab.PinnedArray, _offset, _length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,6 @@
|
||||||
// Copyright (c) Microsoft. All rights reserved.
|
// Copyright (c) Microsoft. All rights reserved.
|
||||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||||
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace System.Buffers
|
namespace System.Buffers
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -11,18 +9,9 @@ namespace System.Buffers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class MemoryPoolSlab : IDisposable
|
internal class MemoryPoolSlab : IDisposable
|
||||||
{
|
{
|
||||||
/// <summary>
|
private MemoryPoolSlab(byte[] pinnedData)
|
||||||
/// 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.
|
|
||||||
/// </summary>
|
|
||||||
private GCHandle _gcHandle;
|
|
||||||
private bool _isDisposed;
|
|
||||||
|
|
||||||
public MemoryPoolSlab(byte[] data)
|
|
||||||
{
|
{
|
||||||
Array = data;
|
PinnedArray = pinnedData;
|
||||||
_gcHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
|
|
||||||
NativePointer = _gcHandle.AddrOfPinnedObject();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -30,51 +19,24 @@ namespace System.Buffers
|
||||||
/// memory pool size an entire slab must be removed. That is done by (1) setting IsActive to false and removing 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
|
/// 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
|
/// 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
|
/// collected and the slab is no longer references the slab will be garbage collected
|
||||||
/// be unpinned by the slab's Dispose.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsActive => !_isDisposed;
|
public bool IsActive => PinnedArray != null;
|
||||||
|
|
||||||
public IntPtr NativePointer { get; private set; }
|
public byte[] PinnedArray { get; private set; }
|
||||||
|
|
||||||
public byte[] Array { get; private set; }
|
|
||||||
|
|
||||||
public static MemoryPoolSlab Create(int length)
|
public static MemoryPoolSlab Create(int length)
|
||||||
{
|
{
|
||||||
// allocate and pin requested memory length
|
// allocate requested memory length from the pinned memory heap
|
||||||
var array = new byte[length];
|
var pinnedArray = GC.AllocateUninitializedArray<byte>(length, pinned: true);
|
||||||
|
|
||||||
// allocate and return slab tracking object
|
// allocate and return slab tracking object
|
||||||
return new MemoryPoolSlab(array);
|
return new MemoryPoolSlab(pinnedArray);
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Dispose(true);
|
PinnedArray = null;
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace System.Buffers
|
namespace System.Buffers
|
||||||
|
|
@ -110,7 +111,8 @@ namespace System.Buffers
|
||||||
var slab = MemoryPoolSlab.Create(_slabLength);
|
var slab = MemoryPoolSlab.Create(_slabLength);
|
||||||
_slabs.Push(slab);
|
_slabs.Push(slab);
|
||||||
|
|
||||||
var basePtr = slab.NativePointer;
|
// Get the address for alignment
|
||||||
|
IntPtr basePtr = Marshal.UnsafeAddrOfPinnedArrayElement(slab.PinnedArray, 0);
|
||||||
// Page align the blocks
|
// Page align the blocks
|
||||||
var offset = (int)((((ulong)basePtr + (uint)_blockSize - 1) & ~((uint)_blockSize - 1)) - (ulong)basePtr);
|
var offset = (int)((((ulong)basePtr + (uint)_blockSize - 1) & ~((uint)_blockSize - 1)) - (ulong)basePtr);
|
||||||
// Ensure page aligned
|
// Ensure page aligned
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue