Zero Heap Use
ListMemory<L, T>, MemoryMemory<T>, PointerMemory<T> and Slice are structs. They can be used with zero heap allocations by not boxing as IMemory<T>.
byte[] array = new byte[50];
// Create fixed-sized memory
var arrayMemory = new MemoryMemory<byte>(array);
// Adapt to variable-sized
var arrayMemoryAllocation = new Slice<MemoryMemory<byte>, byte>(
decoree: arrayMemory,
offset: 10L,
count: 9L,
allocation: 20L);
ArrayPool
ListMemory<L, T> can adapt array pool rented recyclable blocks into memory access.
// Rent array
byte[] array = ArrayPool<byte>.Shared.Rent(50);
try
{
// Create fixed-sized memory
var arrayMemory = new MemoryMemory<byte>(array);
// Adapt to variable-sized
var arrayMemoryAllocation = new Slice<MemoryMemory<byte>, byte>(
decoree: arrayMemory,
offset: 10L,
count: 9L,
allocation: 20L);
WriteLine(arrayMemory.IsFixedSize); // 'True'
WriteLine(arrayMemoryAllocation.IsFixedSize); // 'False'
WriteLine(arrayMemoryAllocation.Count); // '9'
WriteLine(arrayMemoryAllocation.MaxCount); // '20'
// Modify content
arrayMemoryAllocation.Add(item: 10);
arrayMemoryAllocation.Insert(0L, 9);
arrayMemoryAllocation.Count = 5L;
// Clear
arrayMemoryAllocation.Clear();
WriteLine(arrayMemoryAllocation.Count); // '0'
}
finally
{
// Return
ArrayPool<byte>.Shared.Return(array);
}
Span<T>
PointerMemory<T> adapts Span<T> into memory in an unsafe pointer assignment.
// Element count
int count = 4096;
// Allocate from from stack (Note that there is 1.5MB of stack per thread)
Span<byte> buf = stackalloc byte[count];
// Adapt to memory access
var bufMemory = new PointerMemory<byte>(buf);
// Adapt to variable-sized
var slice = new Slice<PointerMemory<byte>, byte>(
decoree: bufMemory,
offset: 0L,
count: 0L,
allocation: count);
// Increment content to 'buf'
for (int i = 0; i < 4096; i++)
slice.Add((byte)i);
Block Pool
BlockMemory rents blocks from array pool. BlockPool itself is a heap object, but the content is held in recyclable blocks when pool is provided as constructor argument.
// Create array pool allocating
using IMemory<byte> memory = new BlockMemory<byte>(ArrayBlockPool<byte>.Instance) { LazyAllocate = true, ClearReturnedBlocks = false };
// Allocate
memory.Count = 4096L;
Rental Memory
BlockMemory<T>.CleanPool.Rent() rents a memory from object pool. Dispose() returns it to the pool. The rented memory is not synchronzied for concurrent usage as is.
// Rent dirty memory (non-synchronized)
IMemory<byte> memory = BlockMemory<byte>.CleanPool.Rent();
// Allocate 100GB (lazy)
memory.Count = 100L * 1024L * 1024L * 1024L;
// Return to pool
memory.Dispose();
BlockMemory<T>.DirtyPool.Rent() doesn't zero pages upon rent or return. Previous data mat be revealed. This version is used for non-security critical, highly efficient "zero heap" heap-assignable memory objects.
// Rent dirty memory (non-synchronized)
IMemory<byte> memory = BlockMemory<byte>.DirtyPool.Rent();
// Allocate 100GB (lazy)
memory.Count = 100L * 1024L * 1024L * 1024L;
// Return to pool
memory.Dispose();
Both pools use the same ArrayPool<T>.Shared.
Full Example
Full example
using System.Buffers;
using Avalanche.Memory;
using static System.Console;
public class zeroheap
{
public static void Run()
{
{
// <01>
byte[] array = new byte[50];
// Create fixed-sized memory
var arrayMemory = new MemoryMemory<byte>(array);
// Adapt to variable-sized
var arrayMemoryAllocation = new Slice<MemoryMemory<byte>, byte>(
decoree: arrayMemory,
offset: 10L,
count: 9L,
allocation: 20L);
// </01>
}
{
// <11>
// Rent array
byte[] array = ArrayPool<byte>.Shared.Rent(50);
try
{
// Create fixed-sized memory
var arrayMemory = new MemoryMemory<byte>(array);
// Adapt to variable-sized
var arrayMemoryAllocation = new Slice<MemoryMemory<byte>, byte>(
decoree: arrayMemory,
offset: 10L,
count: 9L,
allocation: 20L);
WriteLine(arrayMemory.IsFixedSize); // 'True'
WriteLine(arrayMemoryAllocation.IsFixedSize); // 'False'
WriteLine(arrayMemoryAllocation.Count); // '9'
WriteLine(arrayMemoryAllocation.MaxCount); // '20'
// Modify content
arrayMemoryAllocation.Add(item: 10);
arrayMemoryAllocation.Insert(0L, 9);
arrayMemoryAllocation.Count = 5L;
// Clear
arrayMemoryAllocation.Clear();
WriteLine(arrayMemoryAllocation.Count); // '0'
}
finally
{
// Return
ArrayPool<byte>.Shared.Return(array);
}
// </11>
}
{
// <21>
// Element count
int count = 4096;
// Allocate from from stack (Note that there is 1.5MB of stack per thread)
Span<byte> buf = stackalloc byte[count];
// Adapt to memory access
var bufMemory = new PointerMemory<byte>(buf);
// Adapt to variable-sized
var slice = new Slice<PointerMemory<byte>, byte>(
decoree: bufMemory,
offset: 0L,
count: 0L,
allocation: count);
// Increment content to 'buf'
for (int i = 0; i < 4096; i++)
slice.Add((byte)i);
// </21>
}
{
// <31>
// Create array pool allocating
using IMemory<byte> memory = new BlockMemory<byte>(ArrayBlockPool<byte>.Instance) { LazyAllocate = true, ClearReturnedBlocks = false };
// Allocate
memory.Count = 4096L;
// </31>
}
{
// <41>
// Rent dirty memory (non-synchronized)
IMemory<byte> memory = BlockMemory<byte>.CleanPool.Rent();
// Allocate 100GB (lazy)
memory.Count = 100L * 1024L * 1024L * 1024L;
// Return to pool
memory.Dispose();
// </41>
}
{
// <42>
// Rent dirty memory (non-synchronized)
IMemory<byte> memory = BlockMemory<byte>.DirtyPool.Rent();
// Allocate 100GB (lazy)
memory.Count = 100L * 1024L * 1024L * 1024L;
// Return to pool
memory.Dispose();
// </42>
}
}
}