ArrayPool是一个抽象类,框架没有暴露具体实现类,只是通过ArrayPool类的静态方法创建或者获取一个ArrayPool类的实例,并且框架内部所有通过抽象类暴露接口的实现也都是线程安全的
ArrayPool类的作用相当于数组所有权转移的中间代理者,可以从池中租用一块大小不小于指定长度的数组,如果当前池中没有可用数组实例会自动创建一个,当使用完毕后可以将数组返还池中,池中有一个阈值,会自动放弃多余数组的引用,这样数组就会被GC回收(若没有其他引用存在),所以根据实现租用了不返回并不会造成致命问题,但是将池中租用的数组实例返回池中后继续使用或者返回了大于一次则是致命错误
可以通过两种方式获取ArrayPool的实例,一个是通过静态属性Shared获取一个公共实例,因为ArrayPool是泛型类型,所以每一个通过泛型参数具体化的类都有一个独立的公共实例
ArrayPool<byte> byteArrayPool = ArrayPool<byte>.Shared; ArrayPool<char> charArrayPool = ArrayPool<char>.Shared; Console.WriteLine(object.ReferenceEquals(byteArrayPool, charArrayPool));
另一个方法是通过静态方法Create创建一个新的实例,Create方法有两个参数的重载
public static ArrayPool<T> Create (int maxArrayLength, int maxArraysPerBucket);
通过这个重载我们可以自定义池的容量,池中会将长度相似的数组实例放到一个“桶”中,每个“桶”中的数组实例的个数不超过maxArraysPerBucket,并且池中数组实例的最大长度不超过maxArrayLength,(个人猜测这也限制了“桶”的数量)
ArrayPool<byte> byteArrayPool = ArrayPool<byte>.Create(81920, 10);
有一个区别是这两个方法获得的池的具体内部实现类并不一样
//输出 System.Buffers.TlsOverPerCoreLockedStacksArrayPool`1[System.Byte] Console.WriteLine(ArrayPool<byte>.Shared.GetType()); //输出 System.Buffers.ConfigurableArrayPool`1[System.Byte] Console.WriteLine(ArrayPool<byte>.Create(81920, 10).GetType());
租用数组使用实例方法Rent(int minimumLength),注意此方法返回的内存长度保证不会小于minimumLength,但可能大于minimumLength,并且根据返还池中时的选项,数组中可能包含上一次租用时所使用的数据
返还数组使用实例方法Return(T[] array, bool clearArray = false),第一个参数就是将要返还的数组,返还数组代表所有权的转移。第二个参数默认值为false,如果为true的话,会将数组的内容清0,若数组是引用类型的数组并且clearArray为false的话那么数组中所引用的实例可能不会被GC回收(除非池中到达阈值没有保留数组的引用)
string[] strs = ArrayPool<string>.Shared.Rent(1024); //使用数组 //... ArrayPool<string>.Shared.Return(strs, true);
