我知道使用的内部缓冲区IMemoryOwner<byte>.Memory
可能比要求的要大。但是,是IMemoryOwner<byte>.Memory.Length
用我问的还是用内部缓冲区的大小定义的?该文件似乎不够准确。
问问题
61 次
1 回答
2
让我们来看看。
MemoryPool<T>.Rent
是抽象的,所以我们将去寻找一个实现。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
给了我们一个正确大小的数组......
这又是抽象的,但我们可以在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];
}
我们可以看到池中有多个桶,每个桶包含指定大小的数组。此方法是查找刚好大于请求大小的数组桶;如果那个桶是空的,它会去寻找更大的桶。如果它没有找到任何东西,它会创建一个带有桶大小的新数组;只有当请求的大小大于池可以管理的大小时,它才会创建一个精确请求大小的数组。
因此,底层数组不太可能Memory<T>
具有请求的大小,并且构造的构造Memory<T>
不会假装Memory<T>
小于其底层数组。
结论是IMemoryOwner<byte>.Memory.Length
确实可以比要求的大。
于 2021-12-01T11:09:43.657 回答