Measure first. Observe allocation rate, heap size, Gen 0/1/2 collections, large-object-heap size, pause time, and request latency with `dotnet-counters`; capture a trace or dump to identify allocating call stacks and retained objects. A high allocation rate and a memory leak are different: a leak shows objects remaining reachable after collections. Common reductions include avoiding repeated materialization, streaming large results, reusing buffers through `ArrayPool<T>`, removing unnecessary string conversions, and selecting collections with sensible capacity. ```csharp public static async Task CopyAsync(Stream input, Stream output, CancellationToken ct) { byte[] buffer = ArrayPool<byte>.Shared.Rent(64 * 1024); try { int read; while ((read = await input.ReadAsync(buffer.AsMemory(0, buffer.Length), ct)) > 0) await output.WriteAsync(buffer.AsMemory(0, read), ct); } finally { ArrayPool<byte>.Shared.Return(buffer, clearArray: true); } } ``` Do not pool small objects blindly; pooling adds lifetime and thread-safety complexity. Benchmark the changed hot path and confirm that allocation savings improve real latency or throughput rather than shifting cost elsewhere.
Prince Yadav · · 0 likes