This project demonstrates real-world memory leak scenarios in .NET Core.
It is designed to help developers understand, reproduce, and detect memory leaks using tools like dotMemory and Visual Studio Diagnostic Tools.
- .NET 7 or 8 SDK
- Visual Studio or VS Code
- (Optional) JetBrains dotMemory
dotnet run
Once running, open Swagger UI to explore available endpoints.
Method | Endpoint | Description |
---|---|---|
GET | /api/leakdemo/products |
/api/leakdemo/products |
POST | /api/leakdemo/event-handler-leak |
Simulates leak via event subscription |
GET | /api/leakdemo/status |
Displays current memory usage |
This scenario demonstrates a memory leak caused by registering DbContext as a Singleton instead of Scoped. The DbContext should be created per request to avoid retaining resources and causing memory leaks.
public class AppDbContext : DbContext
{
public DbSet<Product> Products { get; set; }
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options) { }
}
public void ConfigureServices(IServiceCollection services)
{
// Incorrectly registering DbContext as Singleton (This can cause Memory Leak)
services.AddSingleton<AppDbContext>(provider =>
{
var options = new DbContextOptionsBuilder<AppDbContext>()
.UseSqlite("Data Source=app.db")
.Options;
return new AppDbContext(options);
});
services.AddControllers();
}
By calling the API that interacts with the DbContext, memory usage will steadily increase as new instances of DbContext are not disposed of correctly.
Impact of Memory Leak: The DbContext instance will persist across the application’s lifetime.
This results in memory consumption being constantly high.
The proper approach is to register DbContext as Scoped to ensure it is disposed of after each request.
services.AddScoped<AppDbContext>();
By doing this, you allow the DbContext to be disposed of automatically, freeing up memory and avoiding leaks.
Memory leak caused by not unsubscribing from events, leading to retained references.
publisher.OnEvent += HandleEvent;
// Object can't be garbage collected due to active event subscription
Even if references are removed, the event delegate chain keeps them alive.
Use the /status
endpoint to monitor memory usage in real-time:
GET /api/leakdemo/status
Sample response:
{
"TotalMemoryBytes": 5242880,
"TotalMemoryMB": 5.0,
"GC_Generation0": 4,
"GC_Generation1": 2,
"GC_Generation2": 1
}
- Run the app in Debug mode.
- Open Debug > Windows > Show Diagnostic Tools.
- Select the Memory Usage tab.
- Click Take Snapshot before and after leak calls.
- Analyze object growth and garbage collection behavior.
- Start a profiling session.
- Trigger memory leaks using API endpoints.
- Take snapshots and compare.
- Explore retained paths and memory roots.
### DbContext Singleton Leak
GET http://localhost:5024/api/leakdemo/products
### Event Handler Leak
POST http://localhost:5024/api/leakdemo/event-handler-leak?count=1000
### Memory Status
GET http://localhost:5024/api/leakdemo/status
Alexander(Alireza)
Software .NET Engineer | Memory Optimization Enthusiast
🔗 LinkedIn • 🌐 GitHub