You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让ArrayPool返回指定精确大小的数组?

从ArrayPool获取精确大小数组的需求与问题

在.NET Standard 2.0中,ArrayPool<byte>.Rent(int minLength)方法返回的byte[]大小至少为minLength,但实际可能更大。我的流式框架属于内存/IO密集型场景,其中部分遗留加密提供程序仅接受固定特定大小(如256、512)的byte[];同时如果数组进入Gen2会引发内存膨胀问题。

由于方法签名限制,无法使用Span<T>/ArraySegment<T>等类型来适配。我希望复用ArrayPool的对象池机制,不想自行实现对象池,同时允许使用unsafe代码,曾考虑过封送/映射同一块内存,但不确定可行性。


尝试的解决方案:修改数组长度的辅助类

在他人协助下编写了一个辅助类,通过unsafe方式修改数组的长度字段,返回精确大小的可释放数组对象:

public static class ArrayPoolHelper
{
    /// <summary>
    /// 从指定数组池获取精确大小的可释放缓冲区
    /// </summary>
    /// <param name="pool">要使用的数组池</param>
    /// <param name="size">期望的缓冲区大小</param>
    /// <typeparam name="T">数组元素类型</typeparam>
    /// <returns>包含精确大小缓冲区的可释放对象</returns>
    /// <exception cref="ArgumentNullException"></exception>
    /// <exception cref="ArgumentOutOfRangeException"></exception>
    public static IRentedArray<T> RentExact<T>(ArrayPool<T> pool, int size)
    {
        if (pool == null)
            throw new ArgumentNullException(nameof(pool));
        if (size <= 0)
        {
            throw new ArgumentOutOfRangeException(nameof(size));
        }

        var rented = pool.Rent(size);
        var originalSize = UnsafeChangeLength(rented, (uint)size);
        return new RentedArray<T>(rented, originalSize, pool);
    }

    private static uint UnsafeChangeLength<T>(T[] array, uint newLength)
    {
        if (array.Length == newLength)
            return newLength;
        
        var unsafeRented = Unsafe.As<RawArrayData>(array);
        var originalLength = unsafeRented.Length;
        unsafeRented.Length = newLength;
        return originalLength;
    }

    private sealed class RentedArray<T> : IRentedArray<T>
    {
        private readonly uint _originalSize;
        private readonly ArrayPool<T> _pool;
        private readonly T[] _original;
        private bool _disposed;
        public T[] Data => _disposed ? throw new ObjectDisposedException(ToString()) : _original;

        public RentedArray(T[] original, uint originalSize, ArrayPool<T> pool)
        {
            _originalSize = originalSize;
            _pool = pool;
            _original = original;
        }

        public void Dispose()
        {
            if (_disposed)
                return;
            UnsafeChangeLength(_original, _originalSize);
            _pool.Return(_original, true);
            _disposed = true;
        }
    }

    private sealed class RawArrayData {
        public uint Length;
    }
}

使用方式:

using var rented = ArrayPoolHelper.RentExact(pool, 123);
Assert.AreEqual(rented.Data.Length, 123);

方案问题:并行场景下的CLR错误

后续测试发现,上述通过unsafe修改数组长度的方式,在并行调用时会抛出CLR错误,说明直接修改数组的内部长度字段并非安全可行的方案。


内容的提问来源于stack exchange,提问作者eocron

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 15:32:38