EonaCat.MemoryGuard
1.1.1
Prefix Reserved
dotnet add package EonaCat.MemoryGuard --version 1.1.1
NuGet\Install-Package EonaCat.MemoryGuard -Version 1.1.1
<PackageReference Include="EonaCat.MemoryGuard" Version="1.1.1" />
<PackageVersion Include="EonaCat.MemoryGuard" Version="1.1.1" />
<PackageReference Include="EonaCat.MemoryGuard" />
paket add EonaCat.MemoryGuard --version 1.1.1
#r "nuget: EonaCat.MemoryGuard, 1.1.1"
#:package EonaCat.MemoryGuard@1.1.1
#addin nuget:?package=EonaCat.MemoryGuard&version=1.1.1
#tool nuget:?package=EonaCat.MemoryGuard&version=1.1.1
EonaCat.MemoryGuard
** Automatic memory leak detector for .NET **
EonaCat MemoryGuard is a fully automatic memory leak detection and remediation system with ML-based predictions, pattern detection, and real-time monitoring. Just start once and let it handle everything.
🚀 Features
Fully Automatic Operation
- ✅ Zero manual tracking - Automatically profiles ALL allocations
- ✅ Self-optimizing with machine learning predictions
- ✅ Auto-remediation when memory health deteriorates
- ✅ Background analysis with zero blocking
Advanced Detection
- 🔍 Pattern Detection: Cyclic allocation, spiral leaks, event handler leaks, collection growth, cache bloat
- 🎯 ML-Based Predictions: Predicts future leaks before they happen
- 📊 Health Scoring: Real-time health score (0-100) with actionable recommendations
- 🧠 Retention Path Discovery: Finds what's holding objects in memory
Monitoring
- 📈 Real-time allocation tracking with weak references
- 💾 Generation-based analysis (Gen0, Gen1, Gen2)
- 🔥 Large Object Heap (LOH) monitoring
- 📉 Heap fragmentation analysis
- ⚡ Performance metrics and allocation rates
Auto-Remediation
- 🔧 Automatic leak fixing attempts
- 🚨 Emergency optimization on OutOfMemoryException
- 📋 Complete remediation history
- ⚙️ Configurable remediation strategies
Reporting
- 📄 JSON reports auto-saved to disk
- 🎨 Pretty console output with emojis
- 📑 Programmatic report generation
📦 Installation
Via NuGet
dotnet add package EonaCat.MemoryGuard
🎯 Quick Start
One-Line Initialization (Development)
using EonaCat.MemoryGuard;
// That's it! Everything is now monitored automatically!
MemoryGuard.StartDevelopment();
One-Line Initialization (Production)
// Optimized for production with auto-reports and auto-remediation
MemoryGuard.StartProduction();
Custom Configuration
using EonaCat.MemoryGuard;
// Fluent API for custom configuration
new MemoryGuardBuilder()
.WithMonitoringInterval(TimeSpan.FromSeconds(15))
.WithMemoryThreshold(4L * 1024 * 1024 * 1024) // 4GB
.WithAutoRemediation(true)
.WithAutoReports(true)
.WithStackTraces(true)
.Start();
Manual Configuration
var config = new MemoryGuardConfiguration
{
MonitoringInterval = TimeSpan.FromSeconds(30),
AnalysisInterval = TimeSpan.FromMinutes(2),
PredictionInterval = TimeSpan.FromMinutes(5),
MemoryPressureThreshold = 2L * 1024 * 1024 * 1024, // 2GB
CaptureStackTraces = true,
EnableAutoRemediation = true,
AutoSaveReports = true
};
MemoryGuard.Start(_config);
💡 Usage Examples
Subscribe to Events
var detector = MemoryGuard.Instance;
// Leak detection
detector.LeakDetected += (s, e) =>
{
Console.WriteLine($"🔴 LEAK DETECTED");
Console.WriteLine($" Type: {e.LeakInfo.TypeName}");
Console.WriteLine($" Age: {e.LeakInfo.Age}");
Console.WriteLine($" Size: {e.LeakInfo.EstimatedSize.ToHumanReadable()}");
Console.WriteLine($" Retention Path: {e.LeakInfo.RetentionPath}");
};
// Memory pressure
detector.MemoryPressureDetected += (s, e) =>
{
Console.WriteLine($"⚠️ MEMORY PRESSURE");
Console.WriteLine($" Current: {e.CurrentMemory.ToHumanReadable()}");
Console.WriteLine($" Threshold: {e.Threshold.ToHumanReadable()}");
Console.WriteLine($" Health: {e.HealthScore.Grade}");
Console.WriteLine($" Recommendation: {e.Recommendation}");
Console.WriteLine($" Time to OOM: {e.PredictedTimeToOOM}");
};
// Pattern detection
detector.PatternDetected += (s, e) =>
{
Console.WriteLine($"{e.Pattern.Severity.GetSeverityEmoji()} PATTERN DETECTED");
Console.WriteLine($" Type: {e.Pattern.Type}");
Console.WriteLine($" Description: {e.Pattern.Description}");
Console.WriteLine($" Confidence: {e.Pattern.Confidence:P0}");
Console.WriteLine($" Action: {e.Pattern.RecommendedAction}");
};
// Large allocations
detector.LargeAllocationDetected += (s, e) =>
{
Console.WriteLine($"📦 LARGE ALLOCATION");
Console.WriteLine($" Type: {e.Type.Name}");
Console.WriteLine($" Size: {e.Size.ToHumanReadable()}");
Console.WriteLine($" Is LOH: {e.IsLOH}");
};
// Leak predictions
detector.LeakPredicted += (s, e) =>
{
Console.WriteLine($"🔮 LEAK PREDICTION");
Console.WriteLine($" Type: {e.PredictedType.Name}");
Console.WriteLine($" Confidence: {e.Confidence:P0}");
Console.WriteLine($" ETA: {e.EstimatedTimeToLeak}");
Console.WriteLine($" Action: {e.RecommendedAction}");
};
// Auto-remediation
detector.AutoRemediationPerformed += (s, e) =>
{
Console.WriteLine($"🔧 AUTO-REMEDIATION");
Console.WriteLine($" Action: {e.Action.ActionTaken}");
Console.WriteLine($" Success: {e.Action.Success}");
Console.WriteLine($" Time: {e.Action.Timestamp}");
};
Get Instant Health Check
var health = MemoryGuard.GetHealthCheck();
Console.WriteLine(health);
// Output:
// ╔══════════════════════════════════════════╗
// ║ EONACAT MEMORY GUARD ║
// ║ HEALTH CHECK ║
// ╠══════════════════════════════════════════╣
// ║ 🟢 GOOD - 75/100 ║
// ║ Memory: 512.5 MB ║
// ║ Objects: 45,231 ║
// ║ Rate: 2.3 MB/sec ║
// ║ GC Pressure: 0.15/min ║
// ╚══════════════════════════════════════════╝
Generate Reports
// Beautiful console report
await MemoryGuard.PrintReportAsync();
// Programmatic access
var report = await MemoryGuard.Instance.GenerateAdvancedReportAsync();
Console.WriteLine($"Health: {report.HealthScore.Grade}");
Console.WriteLine($"Leaks: {report.DetectedPatterns.Count}");
Console.WriteLine($"Top Allocator: {report.TopAllocators.First().Type.Name}");
// Simple report
var simpleReport = MemoryGuard.Instance.GenerateReport();
Manual Analysis
// Trigger analysis
var analysis = await MemoryGuard.Instance.AnalyzeAsync();
Console.WriteLine($"Memory: {analysis.TotalMemoryBytes.ToHumanReadable()}");
Console.WriteLine($"Leaked Objects: {analysis.LeakedObjects.Count}");
Console.WriteLine($"Suspicious Objects: {analysis.SuspiciousObjects.Count}");
Console.WriteLine($"Patterns: {analysis.DetectedPatterns.Count}");
Console.WriteLine($"Health Score: {analysis.HealthScore.Score:F0}/100");
Console.WriteLine($"Fragmentation: {analysis.HeapFragmentation.FragmentationPercent:F2}%");
// View leaked objects
foreach (var leak in analysis.LeakedObjects)
{
Console.WriteLine($" - {leak.TypeName}");
Console.WriteLine($" Age: {leak.Age}");
Console.WriteLine($" Size: {leak.EstimatedSize.ToHumanReadable()}");
Console.WriteLine($" Generation: {leak.Generation}");
Console.WriteLine($" Thread: {leak.ThreadId}");
}
Get Statistics
var stats = MemoryGuard.Instance.GetStatistics();
Console.WriteLine($"Total Allocations: {stats.TotalAllocations:N0}");
Console.WriteLine($"Alive Objects: {stats.AliveObjects:N0}");
Console.WriteLine($"Collected Objects: {stats.CollectedObjects:N0}");
Console.WriteLine($"Total Memory: {stats.TotalGCMemory.ToHumanReadable()}");
Console.WriteLine($"Allocation Rate: {stats.AllocationRate.ToHumanReadable()}/sec");
Console.WriteLine($"GC Pressure: {stats.GCPressure:F2} Gen2/min");
Console.WriteLine($"Gen0: {stats.Gen0Objects:N0} objects ({stats.Gen0Collections:N0} collections)");
Console.WriteLine($"Gen1: {stats.Gen1Objects:N0} objects ({stats.Gen1Collections:N0} collections)");
Console.WriteLine($"Gen2: {stats.Gen2Objects:N0} objects ({stats.Gen2Collections:N0} collections)");
View Top Allocators
var topTypes = MemoryGuard.Instance.GetTopAllocators(10);
foreach (var type in topTypes)
{
Console.WriteLine($"{type.Type.Name}:");
Console.WriteLine($" Total Size: {type.TotalSize.ToHumanReadable()}");
Console.WriteLine($" Count: {type.AllocCount:N0}");
Console.WriteLine($" Average: {type.AverageSize.ToHumanReadable()}");
Console.WriteLine($" Peak: {type.PeakSize.ToHumanReadable()}");
Console.WriteLine($" Rate: {type.AllocationRate:F2} allocs/sec");
}
Manual Optimization
// Force garbage collection and cleanup
var result = MemoryGuard.Instance.ForceOptimize();
Console.WriteLine($"Before: {result.BeforeMemory.ToHumanReadable()}");
Console.WriteLine($"After: {result.AfterMemory.ToHumanReadable()}");
Console.WriteLine($"Freed: {result.FreedBytes.ToHumanReadable()}");
Console.WriteLine($"Cleared Objects: {result.ClearedObjects:N0}");
Console.WriteLine($"Removed Allocations: {result.RemovedTrackedAllocations:N0}");
Shutdown
// Stop monitoring and generate final report
MemoryGuard.Shutdown();
📊 What Happens Automatically
Once started, MemoryGuard automatically:
- ✅ Tracks all allocations with weak references (no memory overhead)
- ✅ Monitors memory every 30 seconds (configurable)
- ✅ Analyzes for leaks every 2 minutes (configurable)
- ✅ Detects patterns every 3 minutes (configurable)
- ✅ Predicts future leaks every 5 minutes (configurable)
- ✅ Attempts remediation when health drops below 40
- ✅ Emergency optimization on OutOfMemoryException
- ✅ Saves reports to disk automatically
- ✅ Cleans up dead references in background
- ✅ Generates final report on application exit
🎯 Advanced Features
Pattern Detection
MemoryGuard automatically detects these memory patterns:
- Cyclic Allocation: Repeating memory allocation patterns
- Spiral Leak: Continuous growth with increasing volatility
- Event Handler Leak: Unsubscribed event handlers retaining objects
- Collection Growth: Unbounded collection growth
- Cache Bloat: Oversized caches without eviction policies
Health Scoring System
Real-time health score from 0-100 with grades:
- 90-100: ✅ Excellent - Everything optimal
- 70-89: 🟢 Good - Normal operation
- 50-69: 🟡 Fair - Some concerns
- 30-49: 🟠 Poor - Action needed
- 0-29: 🔴 Critical - Immediate attention required
ML-Based Predictions
- Predicts which types will leak based on historical patterns
- Estimates time to OutOfMemoryException
- Confidence scoring for each prediction
- Recommends preventive actions
Auto-Remediation
When enabled, MemoryGuard automatically:
- Logs detected leaks for investigation
- Performs optimized garbage collection
- Emergency memory cleanup when critical
- Tracks all remediation attempts
⚙️ Configuration Options
public class MemoryGuardConfiguration
{
// Monitoring intervals
TimeSpan MonitoringInterval { get; set; } // Default: 30s
TimeSpan AnalysisInterval { get; set; } // Default: 2m
TimeSpan PredictionInterval { get; set; } // Default: 5m
TimeSpan BackgroundAnalysisInterval { get; set; } // Default: 1m
TimeSpan OptimizationInterval { get; set; } // Default: 10m
TimeSpan PatternDetectionInterval { get; set; } // Default: 3m
// Thresholds
TimeSpan LeakDetectionThreshold { get; set; } // Default: 5m
TimeSpan SuspiciousObjectThreshold { get; set; } // Default: 2m
long MemoryPressureThreshold { get; set; } // Default: 2GB
long LargeAllocationThreshold { get; set; } // Default: 85KB (LOH)
// Features
bool CaptureStackTraces { get; set; } // Default: true
bool EnableLargeObjectHeapCompaction { get; set; } // Default: true
bool GenerateReportOnExit { get; set; } // Default: true
bool AutoSaveReports { get; set; } // Default: true
bool EnableAutoRemediation { get; set; } // Default: true
// Limits
int MaxSnapshotsRetained { get; set; } // Default: 200
}
Preset Configurations
// Default - Balanced for most scenarios
MemoryGuardConfiguration.Default
// Production - Optimized for production environments
MemoryGuardConfiguration.Production
// Development - Verbose monitoring for debugging
MemoryGuardConfiguration.Development
🌐 Platform Support
- ✅ .NET Framework 4.6.1+
- ✅ .NET Core 2.0+
- ✅ .NET 5/6/7/8
- ✅ Windows
- ✅ Linux
- ✅ macOS
No external dependencies required!
📁 Report Output
Reports are automatically saved to:
{ApplicationDirectory}/EonaCatMemoryGuard/Reports/MemoryReport_YYYYMMDD_HHMMSS.json
Example report structure:
{
"GeneratedAt": "2025-01-07T15:30:00.000Z",
"Uptime": "02:15:30",
"TotalTrackedAllocations": 125847,
"HealthScore": 75.5,
"HealthGrade": "Good",
"TotalMemory": 536870912,
"AliveObjects": 45231,
"LeakCount": 3,
"PatternCount": 2
}
🎯 Automatic Tracking Options
Option 1: Explicit Tracking (Recommended)
Track objects as you create them:
// Start MemoryGuard
MemoryGuard.StartDevelopment();
// Track individual objects
var myObject = MemoryGuard.Track(new MyClass());
var list = MemoryGuard.Track(new List());
// Track with identifier
var cache = MemoryGuard.Track(new Dictionary(), "MainCache");
// Track collections
var items = Enumerable.Range(0, 100).Select(i => new Item(i)).ToList();
MemoryGuard.TrackRange(items);
Option 2: Scoped Tracking
Track all objects within a scope:
using (var scope = MemoryGuard.CreateScope("ProcessData"))
{
var data = scope.Track(new DataProcessor());
var buffer = scope.Track(new byte[1024 * 1024]);
data.Process(buffer);
// At disposal, warns if too many objects still alive
}
Option 3: Object Tracker
Create a tracker for a category of objects:
var tracker = MemoryGuard.CreateTracker("UserSessions");
// Track user session objects
foreach (var user in users)
{
var session = tracker.Track(new UserSession(user));
}
// Check how many are still alive
Console.WriteLine($"Active sessions: {tracker.GetAliveCount()}");
Option 4: Extension Method Style
// Usage
var item = new MyClass().Tracked();
var list = new List().Tracked();
Example 1: Event Handler Leak Detection
MemoryGuard.StartDevelopment();
var publisher = MemoryGuard.Track(new EventPublisher());
// Track subscribers
for (int i = 0; i < 100; i++)
{
var subscriber = MemoryGuard.Track(new EventSubscriber(i));
publisher.SomeEvent += subscriber.HandleEvent;
// FORGOT TO UNSUBSCRIBE - MemoryGuard will detect!
}
// Wait for detection
await Task.Delay(10000);
// MemoryGuard will report:
// 🔴 LEAK DETECTED!
// Type: EventSubscriber
// Root Cause: EventHandlerNotUnsubscribed
// Fix: Unsubscribe from events: publisher.SomeEvent -= subscriber.HandleEvent;
Example 2: Cache Without Eviction
MemoryGuard.StartDevelopment();
var cache = MemoryGuard.Track(new Dictionary(), "DataCache");
// Fill cache without limits
for (int i = 0; i < 10000; i++)
{
cache[$"key_{i}"] = new byte[1024];
}
// MemoryGuard will detect:
// 🔴 PATTERN DETECTED!
// Type: CacheBloat
// Recommendation: Implement cache eviction policy
Example 3: Static Reference Leak
public static class GlobalCache
{
private static List _items = new List();
public static void Add(Data item)
{
_items.Add(MemoryGuard.Track(item));
}
}
// MemoryGuard will detect:
// 🔴 LEAK DETECTED!
// Root Cause: StaticReference
// Fix: Remove from static collection when done
Example 4: Scoped Tracking for Request Processing
public async Task ProcessRequest(HttpRequest request)
{
using (var scope = MemoryGuard.CreateScope($"Request-{request.Id}"))
{
var processor = scope.Track(new RequestProcessor());
var context = scope.Track(new ProcessingContext());
await processor.ProcessAsync(context);
// If objects leak, you'll get a warning with the request ID
}
}
Example 5: Testing for Leaks
[Test]
public async Task TestNoMemoryLeaks()
{
MemoryGuard.StartDevelopment();
var tracker = MemoryGuard.CreateTracker("TestObjects");
// Run your code
for (int i = 0; i < 1000; i++)
{
var obj = tracker.Track(new TestObject());
obj.Process();
}
// Force GC
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
// Check for leaks
await Task.Delay(5000);
var analysis = await MemoryGuard.Instance.AnalyzeAsync();
Assert.AreEqual(0, analysis.LeakedObjects.Count,
"Memory leaks detected!");
}
💡 When to Track What
| Object Type | When to Track | Why |
|---|---|---|
| Event Subscribers | Always | High leak risk |
| Caches/Dictionaries | Always | Can grow unbounded |
| Timers | Always | Must be disposed |
| Threads | Always | Can prevent shutdown |
| Large objects (>85KB) | Always | LOH issues |
| Collections | If long-lived | Growth patterns |
| Request/Context objects | In scope | Lifecycle tracking |
| Test objects | In tests | Leak verification |
🐛 Troubleshooting
High Memory Usage from MemoryGuard Itself
Reduce tracking overhead:
var config = MemoryGuardConfiguration.Production;
config.CaptureStackTraces = false; // Saves significant memory
config.MaxSnapshotsRetained = 50; // Reduce snapshot history
MemoryGuard.Start(config);
Missing Reports
Check write permissions:
var reportPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "EonaCatMemoryGuard", "Reports");
Console.WriteLine($"Reports saved to: {reportPath}");
Events Not Firing
Ensure you've started monitoring:
MemoryGuard.Start();
// Events are only fired after Start() is called internally
False Leak Detections
Adjust thresholds:
var config = new MemoryGuardConfiguration();
config.LeakDetectionThreshold = TimeSpan.FromMinutes(10); // Longer threshold
config.SuspiciousObjectThreshold = TimeSpan.FromMinutes(5);
MemoryGuard.Start(config);
📝 Best Practices
Development
// Verbose monitoring with stack traces
MemoryGuard.StartDevelopment();
// Subscribe to all events for visibility
MemoryGuard.Instance.LeakDetected += (s, e) => Debug.WriteLine($"Leak: {e.LeakInfo.TypeName}");
MemoryGuard.Instance.PatternDetected += (s, e) => Debug.WriteLine($"Pattern: {e.Pattern.Type}");
Production
// Optimized settings with auto-remediation
MemoryGuard.StartProduction();
// Only log critical events
MemoryGuard.Instance.MemoryPressureDetected += (s, e) =>
{
if (e.HealthScore.Score < 30)
Logger.Critical($"Memory critical: {e.Recommendation}");
};
Testing
// Monitor a specific test
MemoryGuard.StartDevelopment();
// Run your test
RunMemoryIntensiveTest();
// Get results
var analysis = await MemoryGuard.Instance.AnalyzeAsync();
Assert.True(analysis.LeakedObjects.Count == 0, "Memory leaks detected!");
// Print report
await MemoryGuard.PrintReportAsync();
Continuous Integration
// Add to your CI pipeline
[TestMethod]
public async Task TestForMemoryLeaks()
{
MemoryGuard.StartDevelopment();
// Run your application logic
await RunApplicationWorkload();
// Analyze for leaks
var analysis = await MemoryGuard.Instance.AnalyzeAsync();
// Fail build if leaks detected
Assert.AreEqual(0, analysis.LeakedObjects.Count,
$"Detected {analysis.LeakedObjects.Count} memory leaks!");
// Save report as artifact
var report = await MemoryGuard.Instance.GenerateAdvancedReportAsync();
// Upload report to CI artifacts
}
Using the Generator
Install-Package EonaCat.MemoryGuard.Generator
1. Make your class a partial class
public partial class MyClass
{
}
To Create the class with auto tracking:
var myPartialClassObject = MyClass.Create();
2. Make your class normally
public class MyClass
{
}
Use the Factory for normal classes:
var myClassObject = MemoryGuardFactory_MyClass.Create();
Stop hunting memory leaks manually - let EonaCat MemoryGuard do it automatically!
| 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 was computed. 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 was computed. 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
- EonaCat.Json (>= 2.0.2)
- System.Management (>= 10.0.1)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on EonaCat.MemoryGuard:
| Package | Downloads |
|---|---|
|
EonaCat.MemoryGuard.Generator
MemoryGuard Auto-Track Source Generator |
GitHub repositories
This package is not used by any popular GitHub repositories.