Back to list
christian289

optimizing-memory-allocation

by christian289

ClaudeCode와 함께하는 .NET 개발 튜토리얼

1🍴 0📅 Jan 25, 2026

SKILL.md


name: optimizing-memory-allocation description: "Implements Zero Allocation patterns using Span, ArrayPool, and ObjectPool for memory efficiency in .NET. Use when reducing GC pressure or optimizing high-performance memory operations."

.NET Memory Efficiency, Zero Allocation

A guide for APIs that minimize GC pressure and enable high-performance memory management.

Quick Reference: See QUICKREF.md for essential patterns at a glance.

1. Core Concepts

  • .NET CLR GC Heap Memory Optimization
  • Understanding Stack allocation vs Heap allocation
  • Stack-only types through ref struct

2. Key APIs

APIPurposeNuGet
Span<T>, Memory<T>Stack-based memory slicingBCL
ArrayPool<T>.SharedReduce GC pressure through array reuseBCL
DefaultObjectPool<T>Object poolingMicrosoft.Extensions.ObjectPool
MemoryCacheIn-memory cachingSystem.Runtime.Caching

3. Span, ReadOnlySpan

3.1 Basic Usage

// Zero Allocation when parsing strings
public void ParseData(ReadOnlySpan<char> input)
{
    // String manipulation without Heap allocation
    var firstPart = input.Slice(0, 10);
    var secondPart = input.Slice(10);
}

// Array slicing
public void ProcessArray(int[] data)
{
    Span<int> span = data.AsSpan();
    Span<int> firstHalf = span[..^(span.Length / 2)];
    Span<int> secondHalf = span[(span.Length / 2)..];
}

3.2 String Processing Optimization

// ❌ Bad example: Substring allocates new string
string part = text.Substring(0, 10);

// ✅ Good example: AsSpan has no allocation
ReadOnlySpan<char> part = text.AsSpan(0, 10);

3.3 Using with stackalloc

public void ProcessSmallBuffer()
{
    // Allocate small buffer on Stack (no Heap allocation)
    Span<byte> buffer = stackalloc byte[256];
    FillBuffer(buffer);
}

4. ArrayPool

Reduces GC pressure by reusing large arrays.

4.1 Basic Usage

namespace MyApp.Services;

public sealed class DataProcessor
{
    public void ProcessLargeData(int size)
    {
        // Rent array (minimize Heap allocation)
        var buffer = ArrayPool<byte>.Shared.Rent(size);

        try
        {
            // Use buffer (only use up to requested size)
            ProcessBuffer(buffer.AsSpan(0, size));
        }
        finally
        {
            // Must return
            ArrayPool<byte>.Shared.Return(buffer);
        }
    }
}

4.2 clearArray Option

// Initialize before returning when handling sensitive data
ArrayPool<byte>.Shared.Return(buffer, clearArray: true);

5. ObjectPool

Reuses expensive objects.

namespace MyApp.Services;

using Microsoft.Extensions.ObjectPool;

public sealed class HeavyObjectProcessor
{
    private readonly ObjectPool<HeavyObject> _pool;

    public HeavyObjectProcessor()
    {
        var policy = new DefaultPooledObjectPolicy<HeavyObject>();
        _pool = new DefaultObjectPool<HeavyObject>(policy, maximumRetained: 100);
    }

    public void Process()
    {
        var obj = _pool.Get();

        try
        {
            obj.DoWork();
        }
        finally
        {
            _pool.Return(obj);
        }
    }
}

6. Memory

Unlike Span, can be stored in fields or used in async methods.

public sealed class AsyncProcessor
{
    private Memory<byte> _buffer;

    public AsyncProcessor(int size)
    {
        _buffer = new byte[size];
    }

    // Memory<T> can be used in async methods
    public async Task ProcessAsync()
    {
        await FillBufferAsync(_buffer);
        ProcessData(_buffer.Span);
    }
}

7. Required NuGet Package

<ItemGroup>
  <PackageReference Include="Microsoft.Extensions.ObjectPool" Version="9.0.*" />
</ItemGroup>

8. Important Notes

⚠️ Span Constraints

  • Span<T>, ReadOnlySpan<T> cannot be used with async-await
  • Cannot be boxed (ref struct)
  • Cannot be stored as class field (use Memory)
  • Cannot be captured in lambdas/closures

⚠️ ArrayPool Return Required

  • Arrays rented with Rent() must be returned with Return()
  • Use try-finally pattern
  • Memory leak occurs if not returned

⚠️ Rented Size vs Actual Size

// Array larger than requested may be returned
var buffer = ArrayPool<byte>.Shared.Rent(100);
// buffer.Length >= 100 (not exactly 100)

// Use only requested size when actually using
ProcessBuffer(buffer.AsSpan(0, 100));

9. References

Score

Total Score

65/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

1ヶ月以内に更新

+10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

+5

Reviews

💬

Reviews coming soon