MemoryPool<byte>.Rent(int minBufferSize ) 能否返回比要求的更大的 IMemoryOwner<byte>?
Can MemoryPool<byte>.Rent(int minBufferSize ) capable of returning a IMemoryOwner<byte> bigger than asked?
我知道 IMemoryOwner<byte>.Memory
使用的内部缓冲区可能比要求的要大。但是, IMemoryOwner<byte>.Memory.Length
是用我问的还是用内部缓冲区的大小定义的?文档好像不够准确。
一起来看看
MemoryPool<T>.Rent
is abstract, so we'll go looking for an implementation. ArrayMemoryPool<T>.Rent
看起来是个不错的有代表性的候选人。该实现如下所示:
public sealed override IMemoryOwner<T> Rent(int minimumBufferSize = -1)
{
if (minimumBufferSize == -1)
minimumBufferSize = 1 + (4095 / Unsafe.SizeOf<T>());
else if (((uint)minimumBufferSize) > MaximumBufferSize)
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.minimumBufferSize);
return new ArrayMemoryPoolBuffer(minimumBufferSize);
}
让我们把它追到 ArrayMemoryPoolBuffer
:
private sealed class ArrayMemoryPoolBuffer : IMemoryOwner<T>
{
private T[]? _array;
public ArrayMemoryPoolBuffer(int size)
{
_array = ArrayPool<T>.Shared.Rent(size);
}
public Memory<T> Memory
{
get
{
T[]? array = _array;
if (array == null)
{
ThrowHelper.ThrowObjectDisposedException_ArrayMemoryPoolBuffer();
}
return new Memory<T>(array);
}
}
public void Dispose()
{
T[]? array = _array;
if (array != null)
{
_array = null;
ArrayPool<T>.Shared.Return(array);
}
}
}
new Memory<T>(array)
意味着 Memory<T>.Length
将只是底层数组的大小:我们没有任何逻辑可以让较小的 Memory<T>
包裹较大的数组。那么让我们看看 ArrayPool<T>.Shared.Rent
是否返回一个正确大小的数组...
又是abstract, but we can find an implementation at ConfigurableArrayPool<T>
。该方法的核心是:
int index = Utilities.SelectBucketIndex(minimumLength);
if (index < _buckets.Length)
{
// Search for an array starting at the 'index' bucket. If the bucket is empty, bump up to the
// next higher bucket and try that one, but only try at most a few buckets.
const int MaxBucketsToTry = 2;
int i = index;
do
{
// Attempt to rent from the bucket. If we get a buffer from it, return it.
buffer = _buckets[i].Rent();
if (buffer != null)
{
if (log.IsEnabled())
{
log.BufferRented(buffer.GetHashCode(), buffer.Length, Id, _buckets[i].Id);
}
return buffer;
}
}
while (++i < _buckets.Length && i != index + MaxBucketsToTry);
// The pool was exhausted for this buffer size. Allocate a new buffer with a size corresponding
// to the appropriate bucket.
buffer = new T[_buckets[index]._bufferLength];
}
else
{
// The request was for a size too large for the pool. Allocate an array of exactly the requested length.
// When it's returned to the pool, we'll simply throw it away.
buffer = new T[minimumLength];
}
我们可以看到池中有多个桶,每个桶包含指定大小的数组。此方法正在查找刚好大于请求大小的数组桶;如果那个桶是空的,它会寻找更大的桶。如果找不到任何东西,它会创建一个新数组,其大小为 bucket size;只有当请求的大小大于池可以管理的大小时,它才会创建一个精确请求大小的数组。
所以 Memory<T>
下的数组不太可能具有请求的大小,并且 Memory<T>
的构造不会假装 Memory<T>
小于其下层数组数组。
结论是IMemoryOwner<byte>.Memory.Length
确实可以比请求的大
我知道 IMemoryOwner<byte>.Memory
使用的内部缓冲区可能比要求的要大。但是, IMemoryOwner<byte>.Memory.Length
是用我问的还是用内部缓冲区的大小定义的?文档好像不够准确。
一起来看看
MemoryPool<T>.Rent
is abstract, so we'll go looking for an implementation. ArrayMemoryPool<T>.Rent
看起来是个不错的有代表性的候选人。该实现如下所示:
public sealed override IMemoryOwner<T> Rent(int minimumBufferSize = -1)
{
if (minimumBufferSize == -1)
minimumBufferSize = 1 + (4095 / Unsafe.SizeOf<T>());
else if (((uint)minimumBufferSize) > MaximumBufferSize)
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.minimumBufferSize);
return new ArrayMemoryPoolBuffer(minimumBufferSize);
}
让我们把它追到 ArrayMemoryPoolBuffer
:
private sealed class ArrayMemoryPoolBuffer : IMemoryOwner<T>
{
private T[]? _array;
public ArrayMemoryPoolBuffer(int size)
{
_array = ArrayPool<T>.Shared.Rent(size);
}
public Memory<T> Memory
{
get
{
T[]? array = _array;
if (array == null)
{
ThrowHelper.ThrowObjectDisposedException_ArrayMemoryPoolBuffer();
}
return new Memory<T>(array);
}
}
public void Dispose()
{
T[]? array = _array;
if (array != null)
{
_array = null;
ArrayPool<T>.Shared.Return(array);
}
}
}
new Memory<T>(array)
意味着 Memory<T>.Length
将只是底层数组的大小:我们没有任何逻辑可以让较小的 Memory<T>
包裹较大的数组。那么让我们看看 ArrayPool<T>.Shared.Rent
是否返回一个正确大小的数组...
又是abstract, but we can find an implementation at ConfigurableArrayPool<T>
。该方法的核心是:
int index = Utilities.SelectBucketIndex(minimumLength);
if (index < _buckets.Length)
{
// Search for an array starting at the 'index' bucket. If the bucket is empty, bump up to the
// next higher bucket and try that one, but only try at most a few buckets.
const int MaxBucketsToTry = 2;
int i = index;
do
{
// Attempt to rent from the bucket. If we get a buffer from it, return it.
buffer = _buckets[i].Rent();
if (buffer != null)
{
if (log.IsEnabled())
{
log.BufferRented(buffer.GetHashCode(), buffer.Length, Id, _buckets[i].Id);
}
return buffer;
}
}
while (++i < _buckets.Length && i != index + MaxBucketsToTry);
// The pool was exhausted for this buffer size. Allocate a new buffer with a size corresponding
// to the appropriate bucket.
buffer = new T[_buckets[index]._bufferLength];
}
else
{
// The request was for a size too large for the pool. Allocate an array of exactly the requested length.
// When it's returned to the pool, we'll simply throw it away.
buffer = new T[minimumLength];
}
我们可以看到池中有多个桶,每个桶包含指定大小的数组。此方法正在查找刚好大于请求大小的数组桶;如果那个桶是空的,它会寻找更大的桶。如果找不到任何东西,它会创建一个新数组,其大小为 bucket size;只有当请求的大小大于池可以管理的大小时,它才会创建一个精确请求大小的数组。
所以 Memory<T>
下的数组不太可能具有请求的大小,并且 Memory<T>
的构造不会假装 Memory<T>
小于其下层数组数组。
结论是IMemoryOwner<byte>.Memory.Length
确实可以比请求的大