Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replacing ArrayPool<T> for creating arrays without allocation

Tags:

c#

I have small chunk of code for uploading a video file by reading the file in chunks and transferring it to the API. E.g. simplified

while (someflag)
{
    // open file stream
    reader.Seek(counterHowMuchIsTransferred, SeekOrigin.Begin);
    var buffer = ArrayPool<byte>.Shared.Rent(chunkSize);
    await reader.ReadAsync(buffer.AsMemory(), cancellationToken);
}

Now the problem is that ArrayPool<T>.Shared.Rent() returns minimum requested size, which most of the times returns bigger array and breaks the file upload. How can I fix that without allocating new array every time new byte[chunkSize] because the chunkSize is always over 85K and it will be allocated on LOH.

like image 399
Expressingx Avatar asked Jan 30 '26 04:01

Expressingx


1 Answers

You don't. When using pooled arrays, you need to acknowledge that they will be oversized, and you need to act accordingly - i.e. you need to track what portion is used.

If you tried to create a pool of right-sized arrays: you'd almost never get "hits", i.e. very few callers would ask for exactly the same size.

So: just track what portion is used. You should be doing this anyway - i.e. you almost certainly want to capture the return value of reader.ReadAsync (and probably loop, if it works like most reader APIs do). When you know the final size, just slice that off the chunk; for example:

var memory = buffer.AsMemory();
// ...
memory = memory.Slice(0, totalBytes);
// ..

The handy thing here is that MemoryMarshal.TryGetArray will still return the same array, so even if you just work with Memory<byte> (and don't keep the byte[] conveniently available), you can still recycle the array correctly later.

like image 147
Marc Gravell Avatar answered Feb 01 '26 20:02

Marc Gravell



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!