Skip to main content

dotnext-memory

Allocation-free memory routines from the DotNext and DotNext.Unsafe NuGet packages - SpanOwner (safe stackalloc with pooled fallback), BufferWriterSlim (stack-allocated StringBuilder/buffer replacement with string interpolation), PoolingBufferWriter, PoolingArrayBufferWriter, SparseBufferWriter, and the MemoryAllocator abstraction over ArrayPool, plain arrays and unmanaged memory. Use when reducing allocations in .NET hot paths; when stackalloc length comes from input; when replacing StringBuilder, MemoryStream, RecyclableMemoryStream, ArrayBufferWriter or manual ArrayPool rent/return code; or when making the memory allocation strategy configurable.

소스 정보

저장소
dotnet/dotNext
최근 소스 활동
2026년 10월 6일 14:10
감지된 SKILL.md 언어
영어
스타
1,967
포크
157

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
dotnext-memory
description
Allocation-free memory routines from the DotNext and DotNext.Unsafe NuGet packages - SpanOwner (safe stackalloc with pooled fallback), BufferWriterSlim (stack-allocated StringBuilder/buffer replacement with string interpolation), PoolingBufferWriter, PoolingArrayBufferWriter, SparseBufferWriter, and the MemoryAllocator abstraction over ArrayPool, plain arrays and unmanaged memory. Use when reducing allocations in .NET hot paths; when stackalloc length comes from input; when replacing StringBuilder, MemoryStream, RecyclableMemoryStream, ArrayBufferWriter or manual ArrayPool rent/return code; or when making the memory allocation strategy configurable.
license
MIT
metadata
{"dotnext-version":"6.x"}
# Before you start 1. Check which version of `DotNext` and `DotNext.Unsafe` the project references (`.csproj` or `Directory.Packages.props`). This skill describes 6.x. For older versions, verify each member you use against the XML docs/IntelliSense of the referenced version. 2. The types below are in several namespaces. Add the `using` shown next to each type. 3. If this skill doesn't cover what you need (API details, more examples), find the relevant article in the documentation index: https://dotnet.github.io/dotNext/llms.txt Most of the types are in `DotNext` package. In case of unmanaged memory allocations, add `DotNext.Unsafe` dependency as well. # Use Cases - Avoid **stackalloc** which length is an input from the untrusted source: user input, request parameter, etc. If the length is expected to be small, but you need safe fallback, use `SpanOwner<T>` (`DotNext.Buffers`) data type. - Always declare it with `using`. When the length exceeds the threshold, `SpanOwner<T>` rents the memory from the pool, and `Dispose` returns it. For a stack-allocated span, `Dispose` does nothing. - Choose the threshold in bytes, not elements: divide by `Unsafe.SizeOf<T>()` for other element types. - Canonical example: ```cs using DotNext.Buffers; public static void Encode(ReadOnlySpan<char> input, Stream output, Encoding encoding) { const int stackallocThreshold = 512; // in bytes; keep it small, the stack is limited int maxByteCount = encoding.GetMaxByteCount(input.Length); using SpanOwner<byte> buffer = (uint)maxByteCount <= (uint)stackallocThreshold ? stackalloc byte[maxByteCount] : new SpanOwner<byte>(maxByteCount); var bytesWritten = encoding.GetBytes(input, buffer.Span); output.Write(buffer.Span.Slice(0, bytesWritten)); } ``` - Consider `DotNext.Buffers.BufferWriterSlim<T>` type in combination with extension methods from `DotNext.Buffers.Text.CharBuffer` class instead of `System.Text.StringBuilder` in synchronous code because its initial buffer can be allocated on the stack. If the buffer overflows, the writer uses memory allocator to rent the memory (by default it uses `ArrayPool<T>.Shared`). String interpolation for this type is exposed by the `Interpolate` extension method from `DotNext.Text.StringInterpolation` class. - The initial buffer must have the same element type as the writer: `stackalloc char[...]` for `BufferWriterSlim<char>`. - Keep `Interpolate` outside of the `try` block: calling it on a `BufferWriterSlim<char>` local inside `try`/`finally` fails to compile (CS8347/CS8350), and `using var writer` is not allowed either (CS1657, a `using` variable can't be passed by `ref`). If `Interpolate` throws, the rented buffer is not returned to the pool, which is harmless. - `WrittenSpan` becomes invalid after `Dispose()`. Consume or copy it before. - Canonical example: ```cs using DotNext.Buffers; using DotNext.Text; var writer = new BufferWriterSlim<char>(stackalloc char[256]); writer.Interpolate($"Hello, {name}!"); try { ConsumeWrittenChars(writer.WrittenSpan); } finally { writer.Dispose(); } ``` - Consider `PoolingBufferWriter<T>` (`DotNext.Buffers`) for async scenarios, where `BufferWriterSlim<T>` cannot be applied because it's **ref struct**. Set the expected upper bound of the written data via the `Capacity` init-only property, because the constructor only accepts the memory allocator: `new PoolingBufferWriter<byte>(allocator) { Capacity = 4096 }`. The buffer grows automatically in case of overflow, but each growth rents a larger buffer, copies the written data and returns the smaller buffer to the pool, where it remains retained. Frequent growth therefore costs copying and inflates the pool, so a good initial capacity matters. - Use `PoolingArrayBufferWriter<T>` (`DotNext.Buffers`) instead when the consumer needs the written data as an array: its `WrittenArray` property returns `ArraySegment<T>`, for example to pass to an API that accepts `byte[]` with offset and count. It rents arrays from `ArrayPool<T>`. - Consider `SparseBufferWriter<T>` (`DotNext.Buffers`) if there is no way to guess the initial capacity, and the contiguous buffer is not a requirement. It chains chunks instead of growing a single buffer, so it never copies the written data on growth. The written memory can be enumerated chunk by chunk (`foreach (ReadOnlyMemory<T> chunk in writer)`), copied with `CopyTo`, or obtained as `System.Buffers.ReadOnlySequence<T>` through its `ISupplier<ReadOnlySequence<T>>` implementation. This type is not limited to bytes in contrast to `RecyclableMemoryStream` from `Microsoft.IO.RecyclableMemoryStream` package. - Write through its public `Write`/`Add` methods only. Its `IBufferWriter<T>` members are implemented explicitly because using them can leave holes in the sparse buffer. - Abstract away memory rental and allocation by using `MemoryAllocator<T>` delegate (`DotNext.Buffers`). It can be passed to the types mentioned above, so your application can be configured to use one of the predefined allocation strategies: - `System.Buffers.ArrayPool<T>.Shared` which is exposed by `MemoryAllocator<T>.Default` static property - Plain array allocation without pooling, which is exposed by `MemoryAllocator<T>.Array` static property - Unmanaged heap allocation, which is exposed by `MemoryAllocator<T>.Unmanaged` static extension property, which requires a reference to `DotNext.Unsafe` package - A custom `ArrayPool<T>` or `MemoryPool<T>` can be converted with the `ToAllocator()` extension method
GitHub에서 보기