SharpArena 0.7.17
See the version list below for details.
dotnet add package SharpArena --version 0.7.17
NuGet\Install-Package SharpArena -Version 0.7.17
<PackageReference Include="SharpArena" Version="0.7.17" />
<PackageVersion Include="SharpArena" Version="0.7.17" />
<PackageReference Include="SharpArena" />
paket add SharpArena --version 0.7.17
#r "nuget: SharpArena, 0.7.17"
#:package SharpArena@0.7.17
#addin nuget:?package=SharpArena&version=0.7.17
#tool nuget:?package=SharpArena&version=0.7.17
SharpArena
Zero-alloc arena allocator + collections for high-perf parsers.
This is a pet project originally written for a JsonPath parser as a challenge, but I decided to keep it as a separate lib because I think it's useful.
Samples
Check out the samples directory for complete, end-to-end examples of building a math expression parser with zero managed allocations (outside the arena). Now with Blazor WebAssembly demo — zero managed allocations in the browser
- SimpleMathParser
: A standard .NET console app using
ArenaList,ArenaPtrStack, andArenaStringto tokenize and evaluate expressions. - BlazorMathSymbolicCalculator
: A symbolic calculator Blazor WebAssembly app evaluating math equations in-browser natively without garbage collection.
Reusable Parser Example
The ArenaMathParser extracted for the above samples showcases reusing arena allocations efficiently:
using SharpArena.Allocators;
using var arena = new ArenaAllocator();
// Tokenize the mathematical string into unmanaged tokens inside the arena
var tokens = ArenaMathParser.Tokenize("2 + 3 * x".Replace("x", "10"), arena);
// Evaluate safely allocating on the unmanaged stack internally
double result = ArenaMathParser.Evaluate(tokens, arena);
// Resets pointers and drops all tokens without GC involvement
arena.Reset();
Usage
using SharpArena.Allocators;
using var arena = new ArenaAllocator();
// Memory allocated from arena, invalid after arena is Reset or Disposed
var ptr = arena.Alloc(1024);
arena.Reset();
Collections
SharpArena includes several collection types designed to be backed by the arena allocator. These collections allocate memory from the arena and become invalid when the arena is reset or disposed. They avoid normal GC allocations.
ArenaString
A non-owning view of UTF-16 text stored in unmanaged (arena) memory.
using SharpArena.Collections;
// Clone a managed string or span into the arena
var str = ArenaString.Clone("Hello, World!", arena);
// Can be implicitly cast to ReadOnlySpan<char>
ReadOnlySpan<char> span = str;
// Or explicitly converted back to a managed string
Console.WriteLine(str.ToString());
ArenaString equality and hash codes are both content-based (character data + length), so separately cloned but equal text compares and hashes the same.
When to use: Use ArenaString when you need to store substrings, tokens, or parsed text during parsing or processing without creating System.String allocations for every token.
ArenaList
A dynamic array (list) backed by the arena for unmanaged structs.
using SharpArena.Collections;
var list = new ArenaList<int>(arena, initialCapacity: 16);
list.Add(1);
list.Add(2);
list.Add(3);
foreach (var item in list.AsSpan()) {
Console.WriteLine(item);
}
When to use: Use ArenaList<T> when you need a fast, resizable list of items (like AST nodes or tokens) during a single operation, avoiding GC overhead for arrays.
Note on growth: When dynamic collections like ArenaList double in size, they allocate a new buffer and leave the old buffer alive until Reset() is called. This is fine for short-lived arenas, but if you do a lot of growing in one operation, you're temporarily burning memory that could have been reused. This is a classic bump-allocator edge case.
ArenaPtrStack
A fast, unmanaged stack specifically for pointers.
using SharpArena.Collections;
var stack = new ArenaPtrStack<int>(arena, initialCapacity: 16);
int a = 42;
stack.Push(&a);
var ptr = stack.Pop();
Console.WriteLine(*ptr);
When to use: Use ArenaPtrStack<T> when writing parsers or state machines that need to push and pop pointers to unmanaged memory rapidly.
Comparison with Varena
Varena is another excellent arena allocator library for .NET. Here is a quick comparison to help you choose:
SharpArena
- Internal workings: Uses a linked list of segments (
ArenaSegment), dynamically allocating memory viaNativeMemoryorP/Invokeas needed. Memory is requested in chunks and bumped within the active segment. - Limitations: Over-allocates slightly if many small objects are allocated, since segment sizes double up to a maximum. Requires careful management of unmanaged memory since there are no GC roots.
- When to use: Best for fast parsing scenarios (like parsers or temporary request states) where you want to allocate a batch of objects, possibly strings or lists, and drop them all at once. Includes built-in collections.
Varena
- Internal workings: Leverages virtual memory directly (e.g.,
VirtualAllocon Windows). It reserves a massive contiguous virtual address space upfront and commits physical memory pages strictly as needed. - Limitations: Not available in WASM environments because it requires virtual memory OS APIs.
- When to use: Better when you need to continuous blocks of very large memory without worrying about re-allocations or segment limits, and you are on a supported platform (Windows/Linux/macOS).
Thread Safety
SharpArena is strictly NOT thread-safe.
To achieve maximum performance and zero overhead on the hot path, ArenaAllocator and its associated collections do not use any synchronization primitives (locks, interlocked operations, or volatile reads).
- One Arena Per Thread: You should create a separate
ArenaAllocatorinstance for each thread or use a[ThreadStatic]field. - No Concurrent Access: Do not call
Alloc,Reset, orDisposeconcurrently from multiple threads on the same instance. - Single-Threaded Collections: Collections like
ArenaList<T>andArenaStringare intended to be used within the same thread that owns the arena.
Benchmarks
See bench/ArenaBench.md for performance numbers compared to NativeMemory and Varena.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 is compatible. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- System.Runtime.CompilerServices.Unsafe (>= 6.0.0)
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.7.19 | 21 | 3/21/2026 |
| 0.7.18 | 19 | 3/21/2026 |
| 0.7.17 | 18 | 3/21/2026 |
| 0.7.16 | 19 | 3/21/2026 |
| 0.7.15 | 18 | 3/21/2026 |
| 0.7.14 | 96 | 3/16/2026 |
| 0.7.13 | 84 | 3/16/2026 |
| 0.7.12 | 82 | 3/16/2026 |
| 0.7.11 | 91 | 3/15/2026 |
| 0.7.10 | 76 | 3/15/2026 |
| 0.7.9 | 83 | 3/15/2026 |
| 0.7.8 | 86 | 3/15/2026 |
| 0.7.7 | 85 | 3/14/2026 |
| 0.7.6 | 88 | 3/14/2026 |
| 0.7.5 | 91 | 3/14/2026 |
| 0.7.4 | 159 | 3/14/2026 |
| 0.7.3 | 87 | 3/14/2026 |
| 0.7.2 | 87 | 3/14/2026 |
| 0.7.1 | 90 | 3/14/2026 |
| 0.7.0 | 86 | 3/14/2026 |
- test: add tests for ToArenaList extension method