Home > front end >  Replacing ArrayPool<T> for creating arrays without allocation
Replacing ArrayPool<T> for creating arrays without allocation

Time:09-16

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.

CodePudding user response:

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.

  •  Tags:  
  • c#
  • Related