# Garbage Collection and IDisposable — C#/.NET

Source: https://www.skillbyai.com/en/dotnet/r-gc

> Explain how the GC works and release unmanaged resources with using.

## Automatic memory, manual resources

The .NET **garbage collector (GC)** frees heap memory that is no longer reachable from **roots** (static fields, local variables on thread stacks, CPU registers). It is **generational**: new objects start in **generation 0**, which is collected often and cheaply; survivors are promoted to gen 1 and then gen 2, collected less often. Objects of 85,000 bytes or more go to the **large object heap**. Most short-lived objects die young, so gen 0 collections are fast. The GC manages **memory only**. Files, sockets, database connections and OS handles are **unmanaged resources** that must be released promptly, which is what **`IDisposable`** is for. A **`using` declaration** or `using` block calls `Dispose()` automatically, even if an exception is thrown; `IAsyncDisposable` with `await using` does the same for async cleanup. Finalizers exist for last-resort cleanup of raw handles, but you rarely write one; wrap handles in `SafeHandle` instead.

## Generations of the managed heap

Most objects die young in generation 0; long-lived survivors move to older generations.

![Three horizontal bands from small and busy to large and calm, with many small dots in the first band fading out and a few dots moving down into the later bands.](assets/figures/dotnet/section-7-map.svg) — Figure 7.1 — Gen 0, gen 1 and gen 2, with promotion of survivors.

## Deterministic cleanup with using

Both the file and the connection are closed even if an exception occurs.

```cs
using var writer = new StreamWriter("report.csv");   // disposed at end of scope
writer.WriteLine("id,total");

await using var connection = new SqlConnection(connectionString);
await connection.OpenAsync();

public sealed class TempFile : IDisposable
{
    public string Path { get; } = System.IO.Path.GetTempFileName();
    private bool _disposed;

    public void Dispose()
    {
        if (_disposed) return;
        File.Delete(Path);
        _disposed = true;
    }
}
```

## Do not dispose HttpClient per request

`HttpClient` is the famous exception: creating and disposing one per request can exhaust sockets. Reuse a long-lived instance or use `IHttpClientFactory` in ASP.NET Core.

**Quiz:** What does a `using` declaration guarantee?

- [x] Dispose() is called when the scope ends, even if an exception is thrown
- [ ] The object is garbage-collected immediately
- [ ] The object is allocated on the stack
- [ ] The object becomes thread-safe

*Answer:* Dispose() is called when the scope ends, even if an exception is thrown. using ensures Dispose runs at the end of scope, releasing resources deterministically.
