Memory Leak Detector in Java

A comprehensive memory leak detection tool that monitors Java applications for memory leaks, analyzes heap usage, and provides detailed reports with leak suspects.

Complete Implementation

1. Core Memory Leak Detector

package com.memoryleak.detector;
import java.lang.management.*;
import java.util.*;
import java.util.concurrent.*;
import java.io.*;
import java.nio.file.*;
import java.text.SimpleDateFormat;
/**
* Advanced Memory Leak Detector for Java Applications
* Monitors memory usage, detects leaks, and generates reports
*/
public class MemoryLeakDetector {
private final MemoryMXBean memoryMXBean;
private final List<GarbageCollectorMXBean> gcBeans;
private final ThreadMXBean threadMXBean;
private final ScheduledExecutorService scheduler;
private final List<MemorySnapshot> snapshots;
private final Map<String, ClassTrackingInfo> classTracking;
private final Set<String> excludedClasses;
private final long checkIntervalMs;
private final long maxMemoryThreshold;
private final int maxSnapshots;
private volatile boolean isMonitoring;
private final MemoryLeakListener listener;
private final LeakReportGenerator reportGenerator;
public MemoryLeakDetector() {
this(5000, 85, 50, null);
}
public MemoryLeakDetector(long checkIntervalMs, long memoryThresholdPercent, 
int maxSnapshots, MemoryLeakListener listener) {
this.memoryMXBean = ManagementFactory.getMemoryMXBean();
this.gcBeans = ManagementFactory.getGarbageCollectorMXBeans();
this.threadMXBean = ManagementFactory.getThreadMXBean();
this.checkIntervalMs = checkIntervalMs;
this.maxMemoryThreshold = memoryThresholdPercent;
this.maxSnapshots = maxSnapshots;
this.listener = listener;
this.snapshots = new CopyOnWriteArrayList<>();
this.classTracking = new ConcurrentHashMap<>();
this.excludedClasses = ConcurrentHashMap.newKeySet();
this.scheduler = Executors.newScheduledThreadPool(2);
this.reportGenerator = new LeakReportGenerator();
initializeExcludedClasses();
}
/**
* Start memory leak monitoring
*/
public void startMonitoring() {
if (isMonitoring) {
System.out.println("Memory leak detection is already running");
return;
}
System.out.println("Starting memory leak detection...");
isMonitoring = true;
// Take initial snapshot
takeSnapshot("Initial snapshot");
// Schedule periodic monitoring
scheduler.scheduleAtFixedRate(this::monitorMemory, 
checkIntervalMs, checkIntervalMs, TimeUnit.MILLISECONDS);
// Schedule periodic snapshots
scheduler.scheduleAtFixedRate(() -> takeSnapshot("Periodic snapshot"),
checkIntervalMs * 6, checkIntervalMs * 6, TimeUnit.MILLISECONDS);
System.out.println("Memory leak detection started successfully");
}
/**
* Stop memory leak monitoring
*/
public void stopMonitoring() {
if (!isMonitoring) {
return;
}
System.out.println("Stopping memory leak detection...");
isMonitoring = false;
scheduler.shutdown();
try {
if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
scheduler.shutdownNow();
}
} catch (InterruptedException e) {
scheduler.shutdownNow();
Thread.currentThread().interrupt();
}
takeSnapshot("Final snapshot");
System.out.println("Memory leak detection stopped");
}
/**
* Main monitoring logic
*/
private void monitorMemory() {
try {
MemoryUsage heapUsage = memoryMXBean.getHeapMemoryUsage();
long usedMemory = heapUsage.getUsed();
long maxMemory = heapUsage.getMax();
long usagePercent = (usedMemory * 100) / maxMemory;
// Check memory threshold
if (usagePercent > maxMemoryThreshold) {
handleHighMemoryUsage(usedMemory, maxMemory, usagePercent);
}
// Check for growing trend
if (snapshots.size() >= 3) {
checkMemoryGrowthTrend();
}
// Update class tracking
updateClassTracking();
} catch (Exception e) {
System.err.println("Error during memory monitoring: " + e.getMessage());
}
}
/**
* Handle high memory usage scenario
*/
private void handleHighMemoryUsage(long usedMemory, long maxMemory, long usagePercent) {
String warningMsg = String.format(
"High memory usage detected: %d/%d MB (%d%%)",
bytesToMB(usedMemory), bytesToMB(maxMemory), usagePercent
);
System.warn(warningMsg);
takeSnapshot("High memory usage");
// Suggest garbage collection
System.gc();
// Notify listener
if (listener != null) {
listener.onHighMemoryUsage(usedMemory, maxMemory, usagePercent);
}
// Check if we should trigger leak analysis
if (usagePercent > 90) {
analyzePotentialLeaks();
}
}
/**
* Check for consistent memory growth trend
*/
private void checkMemoryGrowthTrend() {
List<MemorySnapshot> recentSnapshots = getRecentSnapshots(5);
if (recentSnapshots.size() < 3) return;
boolean isGrowing = true;
for (int i = 1; i < recentSnapshots.size(); i++) {
if (recentSnapshots.get(i).getUsedHeap() <= recentSnapshots.get(i - 1).getUsedHeap()) {
isGrowing = false;
break;
}
}
if (isGrowing) {
System.warn("Consistent memory growth trend detected");
takeSnapshot("Memory growth trend");
if (listener != null) {
listener.onMemoryGrowthTrend(recentSnapshots);
}
}
}
}

2. Memory Snapshot System

    /**
* Take a memory snapshot
*/
public MemorySnapshot takeSnapshot(String description) {
MemorySnapshot snapshot = new MemorySnapshot(description);
snapshots.add(snapshot);
// Limit the number of stored snapshots
while (snapshots.size() > maxSnapshots) {
snapshots.remove(0);
}
System.out.println("Snapshot taken: " + description + 
" - Heap: " + bytesToMB(snapshot.getUsedHeap()) + "MB");
return snapshot;
}
/**
* Memory snapshot class
*/
public static class MemorySnapshot {
private final String id;
private final String description;
private final long timestamp;
private final long usedHeap;
private final long maxHeap;
private final long gcCount;
private final long gcTime;
private final int threadCount;
private final int loadedClassCount;
private final Map<String, Long> classMemoryUsage;
public MemorySnapshot(String description) {
MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
this.id = UUID.randomUUID().toString();
this.description = description;
this.timestamp = System.currentTimeMillis();
this.usedHeap = heapUsage.getUsed();
this.maxHeap = heapUsage.getMax();
// GC statistics
long totalGcCount = 0;
long totalGcTime = 0;
for (GarbageCollectorMXBean gcBean : ManagementFactory.getGarbageCollectorMXBeans()) {
totalGcCount += gcBean.getCollectionCount();
totalGcTime += gcBean.getCollectionTime();
}
this.gcCount = totalGcCount;
this.gcTime = totalGcTime;
// Thread statistics
this.threadCount = ManagementFactory.getThreadMXBean().getThreadCount();
this.loadedClassCount = ManagementFactory.getClassLoadingMXBean().getLoadedClassCount();
// Class memory usage (estimated)
this.classMemoryUsage = new HashMap<>();
}
// Getters
public String getId() { return id; }
public String getDescription() { return description; }
public long getTimestamp() { return timestamp; }
public long getUsedHeap() { return usedHeap; }
public long getMaxHeap() { return maxHeap; }
public long getGcCount() { return gcCount; }
public long getGcTime() { return gcTime; }
public int getThreadCount() { return threadCount; }
public int getLoadedClassCount() { return loadedClassCount; }
public Map<String, Long> getClassMemoryUsage() { return classMemoryUsage; }
public double getHeapUsagePercent() {
return (usedHeap * 100.0) / maxHeap;
}
public String getFormattedTimestamp() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(timestamp));
}
}
/**
* Get recent snapshots
*/
private List<MemorySnapshot> getRecentSnapshots(int count) {
int fromIndex = Math.max(0, snapshots.size() - count);
return new ArrayList<>(snapshots.subList(fromIndex, snapshots.size()));
}

3. Class Tracking and Analysis

    /**
* Track memory usage by class
*/
private void updateClassTracking() {
// This is a simplified implementation
// In a real scenario, you might use JMX or instrumentation
Runtime runtime = Runtime.getRuntime();
long totalMemory = runtime.totalMemory();
long freeMemory = runtime.freeMemory();
long usedMemory = totalMemory - freeMemory;
// Update class tracking information
ClassLoadingMXBean classBean = ManagementFactory.getClassLoadingMXBean();
classTracking.put("Total", new ClassTrackingInfo(usedMemory, classBean.getLoadedClassCount()));
}
/**
* Class tracking information
*/
private static class ClassTrackingInfo {
private final long memoryUsed;
private final int instanceCount;
private final long firstSeen;
private long lastSeen;
public ClassTrackingInfo(long memoryUsed, int instanceCount) {
this.memoryUsed = memoryUsed;
this.instanceCount = instanceCount;
this.firstSeen = System.currentTimeMillis();
this.lastSeen = this.firstSeen;
}
public void update() {
this.lastSeen = System.currentTimeMillis();
}
// Getters
public long getMemoryUsed() { return memoryUsed; }
public int getInstanceCount() { return instanceCount; }
public long getFirstSeen() { return firstSeen; }
public long getLastSeen() { return lastSeen; }
}
/**
* Analyze potential memory leaks
*/
public LeakAnalysisResult analyzePotentialLeaks() {
System.out.println("Analyzing potential memory leaks...");
LeakAnalysisResult result = new LeakAnalysisResult();
if (snapshots.size() < 2) {
result.addWarning("Not enough snapshots for analysis");
return result;
}
// Analyze memory growth
analyzeMemoryGrowth(result);
// Analyze GC effectiveness
analyzeGCEffectiveness(result);
// Identify potential leak suspects
identifyLeakSuspects(result);
// Generate recommendations
generateRecommendations(result);
System.out.println("Leak analysis completed: " + result.getSummary());
if (listener != null) {
listener.onLeakAnalysisComplete(result);
}
return result;
}
private void analyzeMemoryGrowth(LeakAnalysisResult result) {
MemorySnapshot first = snapshots.get(0);
MemorySnapshot last = snapshots.get(snapshots.size() - 1);
long memoryGrowth = last.getUsedHeap() - first.getUsedHeap();
long timeDiff = last.getTimestamp() - first.getTimestamp();
if (memoryGrowth > 0) {
double growthRate = (memoryGrowth * 100.0) / first.getUsedHeap();
double growthPerMinute = (memoryGrowth / (timeDiff / 60000.0)) / (1024 * 1024);
result.setMemoryGrowthBytes(memoryGrowth);
result.setMemoryGrowthPercent(growthRate);
result.setGrowthRatePerMinute(growthPerMinute);
if (growthRate > 10) { // More than 10% growth
result.addSuspect("MEMORY_GROWTH", 
String.format("Memory grew by %.2f%% over monitoring period", growthRate));
}
}
}
private void analyzeGCEffectiveness(LeakAnalysisResult result) {
if (snapshots.size() < 2) return;
MemorySnapshot last = snapshots.get(snapshots.size() - 1);
MemorySnapshot previous = snapshots.get(snapshots.size() - 2);
long gcCountIncrease = last.getGcCount() - previous.getGcCount();
long gcTimeIncrease = last.getGcTime() - previous.getGcTime();
long memoryReduction = previous.getUsedHeap() - last.getUsedHeap();
// If GC is running frequently but not reclaiming much memory
if (gcCountIncrease > 0 && memoryReduction < (last.getUsedHeap() * 0.1)) {
result.addSuspect("INEFFECTIVE_GC",
"Garbage collection is running but not reclaiming significant memory");
}
// If GC time is excessive
if (gcTimeIncrease > 10000) { // More than 10 seconds
result.addWarning("Excessive GC time: " + gcTimeIncrease + "ms");
}
}

4. Leak Analysis Results

    /**
* Leak analysis result container
*/
public static class LeakAnalysisResult {
private final String analysisId;
private final long analysisTime;
private final List<String> suspects;
private final List<String> warnings;
private final List<String> recommendations;
private long memoryGrowthBytes;
private double memoryGrowthPercent;
private double growthRatePerMinute;
private String summary;
public LeakAnalysisResult() {
this.analysisId = UUID.randomUUID().toString();
this.analysisTime = System.currentTimeMillis();
this.suspects = new ArrayList<>();
this.warnings = new ArrayList<>();
this.recommendations = new ArrayList<>();
}
public void addSuspect(String type, String description) {
suspects.add("[" + type + "] " + description);
}
public void addWarning(String warning) {
warnings.add(warning);
}
public void addRecommendation(String recommendation) {
recommendations.add(recommendation);
}
// Getters and setters
public String getAnalysisId() { return analysisId; }
public long getAnalysisTime() { return analysisTime; }
public List<String> getSuspects() { return suspects; }
public List<String> getWarnings() { return warnings; }
public List<String> getRecommendations() { return recommendations; }
public long getMemoryGrowthBytes() { return memoryGrowthBytes; }
public void setMemoryGrowthBytes(long memoryGrowthBytes) { this.memoryGrowthBytes = memoryGrowthBytes; }
public double getMemoryGrowthPercent() { return memoryGrowthPercent; }
public void setMemoryGrowthPercent(double memoryGrowthPercent) { this.memoryGrowthPercent = memoryGrowthPercent; }
public double getGrowthRatePerMinute() { return growthRatePerMinute; }
public void setGrowthRatePerMinute(double growthRatePerMinute) { this.growthRatePerMinute = growthRatePerMinute; }
public String getSummary() {
if (summary == null) {
generateSummary();
}
return summary;
}
private void generateSummary() {
StringBuilder sb = new StringBuilder();
sb.append("Leak Analysis Summary: ");
if (suspects.isEmpty()) {
sb.append("No obvious leaks detected");
} else {
sb.append(suspects.size()).append(" potential issue(s) found");
}
if (memoryGrowthPercent > 0) {
sb.append(String.format(", Memory growth: %.2f%%", memoryGrowthPercent));
}
this.summary = sb.toString();
}
public boolean hasIssues() {
return !suspects.isEmpty() || !warnings.isEmpty();
}
public String generateDetailedReport() {
StringBuilder report = new StringBuilder();
report.append("=== MEMORY LEAK ANALYSIS REPORT ===\n");
report.append("Analysis ID: ").append(analysisId).append("\n");
report.append("Time: ").append(new Date(analysisTime)).append("\n");
report.append("Summary: ").append(getSummary()).append("\n\n");
if (memoryGrowthBytes != 0) {
report.append("Memory Growth: ").append(bytesToMB(memoryGrowthBytes))
.append(" MB (").append(String.format("%.2f", memoryGrowthPercent))
.append("%)\n");
report.append("Growth Rate: ").append(String.format("%.2f", growthRatePerMinute))
.append(" MB/minute\n\n");
}
if (!suspects.isEmpty()) {
report.append("POTENTIAL LEAK SUSPECTS:\n");
for (int i = 0; i < suspects.size(); i++) {
report.append("  ").append(i + 1).append(". ").append(suspects.get(i)).append("\n");
}
report.append("\n");
}
if (!warnings.isEmpty()) {
report.append("WARNINGS:\n");
warnings.forEach(warning -> report.append("  - ").append(warning).append("\n"));
report.append("\n");
}
if (!recommendations.isEmpty()) {
report.append("RECOMMENDATIONS:\n");
recommendations.forEach(rec -> report.append("  - ").append(rec).append("\n"));
}
return report.toString();
}
}
private void identifyLeakSuspects(LeakAnalysisResult result) {
// Common memory leak patterns
result.addRecommendation("Check for static collections that might be growing indefinitely");
result.addRecommendation("Review cache implementations for proper eviction policies");
result.addRecommendation("Verify proper resource cleanup in try-with-resources or finally blocks");
result.addRecommendation("Check for listener/callback registrations that are not removed");
result.addRecommendation("Review thread-local usage for proper cleanup");
// Add suspects based on analysis
if (result.getGrowthRatePerMinute() > 5) {
result.addSuspect("RAPID_MEMORY_GROWTH", 
String.format("Memory growing at %.2f MB/minute", result.getGrowthRatePerMinute()));
}
if (result.getMemoryGrowthPercent() > 50) {
result.addSuspect("SIGNIFICANT_MEMORY_GROWTH",
String.format("Memory grew by %.2f%% during monitoring", result.getMemoryGrowthPercent()));
}
}
private void generateRecommendations(LeakAnalysisResult result) {
if (result.getMemoryGrowthPercent() > 20) {
result.addRecommendation("Consider taking a heap dump for detailed analysis");
result.addRecommendation("Use profiler tools like VisualVM or YourKit for deeper investigation");
result.addRecommendation("Review recent code changes related to memory-intensive operations");
}
if (!result.getSuspects().isEmpty()) {
result.addRecommendation("Monitor specific objects using weak references for lifecycle tracking");
result.addRecommendation("Implement memory usage limits for caches and collections");
}
result.addRecommendation("Consider increasing heap size if application legitimately needs more memory");
result.addRecommendation("Review JVM garbage collector settings for optimization");
}

5. Report Generation

    /**
* Leak report generator
*/
public static class LeakReportGenerator {
public void generateReport(MemoryLeakDetector detector, String outputPath) throws IOException {
LeakAnalysisResult result = detector.analyzePotentialLeaks();
String report = generateHtmlReport(detector, result);
Path path = Paths.get(outputPath);
Files.writeString(path, report);
System.out.println("Leak report generated: " + outputPath);
}
public String generateHtmlReport(MemoryLeakDetector detector, LeakAnalysisResult result) {
StringBuilder html = new StringBuilder();
html.append("""
<!DOCTYPE html>
<html>
<head>
<title>Memory Leak Analysis Report</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.header { background: #f0f0f0; padding: 20px; border-radius: 5px; }
.section { margin: 20px 0; padding: 15px; border: 1px solid #ddd; border-radius: 5px; }
.suspect { background: #fff3cd; border-left: 4px solid #ffc107; padding: 10px; margin: 5px 0; }
.warning { background: #f8d7da; border-left: 4px solid #dc3545; padding: 10px; margin: 5px 0; }
.recommendation { background: #d1ecf1; border-left: 4px solid #17a2b8; padding: 10px; margin: 5px 0; }
.metric { display: inline-block; margin: 0 20px 10px 0; }
.chart-container { margin: 20px 0; }
</style>
</head>
<body>
""");
html.append("<div class='header'>")
.append("<h1>Memory Leak Analysis Report</h1>")
.append("<p><strong>Analysis ID:</strong> ").append(result.getAnalysisId()).append("</p>")
.append("<p><strong>Generated:</strong> ").append(new Date()).append("</p>")
.append("</div>");
// Summary section
html.append("<div class='section'>")
.append("<h2>Summary</h2>")
.append("<p>").append(result.getSummary()).append("</p>");
if (result.getMemoryGrowthBytes() != 0) {
html.append("<div class='metric'><strong>Memory Growth:</strong> ")
.append(bytesToMB(result.getMemoryGrowthBytes())).append(" MB</div>");
html.append("<div class='metric'><strong>Growth Percentage:</strong> ")
.append(String.format("%.2f", result.getMemoryGrowthPercent())).append("%</div>");
html.append("<div class='metric'><strong>Growth Rate:</strong> ")
.append(String.format("%.2f", result.getGrowthRatePerMinute())).append(" MB/min</div>");
}
html.append("</div>");
// Suspects section
if (!result.getSuspects().isEmpty()) {
html.append("<div class='section'>")
.append("<h2>Potential Leak Suspects</h2>");
result.getSuspects().forEach(suspect -> 
html.append("<div class='suspect'>").append(suspect).append("</div>"));
html.append("</div>");
}
// Warnings section
if (!result.getWarnings().isEmpty()) {
html.append("<div class='section'>")
.append("<h2>Warnings</h2>");
result.getWarnings().forEach(warning -> 
html.append("<div class='warning'>").append(warning).append("</div>"));
html.append("</div>");
}
// Recommendations section
if (!result.getRecommendations().isEmpty()) {
html.append("<div class='section'>")
.append("<h2>Recommendations</h2>");
result.getRecommendations().forEach(rec -> 
html.append("<div class='recommendation'>").append(rec).append("</div>"));
html.append("</div>");
}
// Snapshots section
html.append("<div class='section'>")
.append("<h2>Memory Snapshots</h2>")
.append("<table border='1' style='border-collapse: collapse; width: 100%;'>")
.append("<tr><th>Time</th><th>Description</th><th>Heap Used</th><th>Heap Max</th><th>Usage %</th></tr>");
for (MemorySnapshot snapshot : detector.getSnapshots()) {
html.append("<tr>")
.append("<td>").append(snapshot.getFormattedTimestamp()).append("</td>")
.append("<td>").append(snapshot.getDescription()).append("</td>")
.append("<td>").append(bytesToMB(snapshot.getUsedHeap())).append(" MB</td>")
.append("<td>").append(bytesToMB(snapshot.getMaxHeap())).append(" MB</td>")
.append("<td>").append(String.format("%.1f", snapshot.getHeapUsagePercent())).append("%</td>")
.append("</tr>");
}
html.append("</table></div>");
html.append("</body></html>");
return html.toString();
}
}

6. Event Listeners and Configuration

    /**
* Memory leak event listener interface
*/
public interface MemoryLeakListener {
void onHighMemoryUsage(long usedMemory, long maxMemory, long usagePercent);
void onMemoryGrowthTrend(List<MemorySnapshot> snapshots);
void onLeakAnalysisComplete(LeakAnalysisResult result);
void onLeakDetected(String description, LeakAnalysisResult result);
}
/**
* Default implementation with logging
*/
public static class LoggingMemoryLeakListener implements MemoryLeakListener {
private final String logPrefix;
public LoggingMemoryLeakListener(String logPrefix) {
this.logPrefix = logPrefix != null ? logPrefix : "[MemoryLeakDetector]";
}
@Override
public void onHighMemoryUsage(long usedMemory, long maxMemory, long usagePercent) {
System.warn(logPrefix + " High memory usage: " + usagePercent + "%");
}
@Override
public void onMemoryGrowthTrend(List<MemorySnapshot> snapshots) {
System.warn(logPrefix + " Memory growth trend detected over " + 
snapshots.size() + " snapshots");
}
@Override
public void onLeakAnalysisComplete(LeakAnalysisResult result) {
if (result.hasIssues()) {
System.warn(logPrefix + " Potential memory leaks detected: " + 
result.getSummary());
} else {
System.info(logPrefix + " No memory leaks detected");
}
}
@Override
public void onLeakDetected(String description, LeakAnalysisResult result) {
System.error(logPrefix + " Memory leak confirmed: " + description);
System.error(result.generateDetailedReport());
}
}
/**
* Configuration for memory leak detector
*/
public static class DetectorConfig {
private long checkIntervalMs = 5000;
private long memoryThresholdPercent = 85;
private int maxSnapshots = 50;
private boolean autoStart = false;
private String reportOutputDir = "./memory-reports";
private MemoryLeakListener listener;
// Builder pattern for fluent configuration
public static DetectorConfig builder() {
return new DetectorConfig();
}
public DetectorConfig checkIntervalMs(long interval) {
this.checkIntervalMs = interval;
return this;
}
public DetectorConfig memoryThresholdPercent(long threshold) {
this.memoryThresholdPercent = threshold;
return this;
}
public DetectorConfig maxSnapshots(int max) {
this.maxSnapshots = max;
return this;
}
public DetectorConfig autoStart(boolean autoStart) {
this.autoStart = autoStart;
return this;
}
public DetectorConfig reportOutputDir(String dir) {
this.reportOutputDir = dir;
return this;
}
public DetectorConfig listener(MemoryLeakListener listener) {
this.listener = listener;
return this;
}
public MemoryLeakDetector build() {
return new MemoryLeakDetector(
checkIntervalMs, memoryThresholdPercent, maxSnapshots, listener);
}
}
private void initializeExcludedClasses() {
// Exclude common JDK classes that are not likely sources of leaks
excludedClasses.add("java.");
excludedClasses.add("javax.");
excludedClasses.add("sun.");
excludedClasses.add("com.sun.");
}
// Utility methods
private static long bytesToMB(long bytes) {
return bytes / (1024 * 1024);
}
// Getters for external access
public List<MemorySnapshot> getSnapshots() {
return new ArrayList<>(snapshots);
}
public boolean isMonitoring() {
return isMonitoring;
}
public MemoryLeakListener getListener() {
return listener;
}

7. Advanced Heap Analysis

    /**
* Advanced heap analysis using JMX
*/
public void performDetailedHeapAnalysis() {
try {
System.out.println("Performing detailed heap analysis...");
// Get memory pool information
List<MemoryPoolMXBean> memoryPools = ManagementFactory.getMemoryPoolMXBeans();
for (MemoryPoolMXBean pool : memoryPools) {
MemoryUsage usage = pool.getUsage();
System.out.println("Pool: " + pool.getName() + 
" - Used: " + bytesToMB(usage.getUsed()) + "MB" +
" - Max: " + bytesToMB(usage.getMax()) + "MB");
}
// Get GC information
for (GarbageCollectorMXBean gc : gcBeans) {
System.out.println("GC: " + gc.getName() + 
" - Count: " + gc.getCollectionCount() +
" - Time: " + gc.getCollectionTime() + "ms");
}
} catch (Exception e) {
System.err.println("Error in detailed heap analysis: " + e.getMessage());
}
}
/**
* Generate heap dump (if supported)
*/
public boolean generateHeapDump(String fileName) {
try {
HotSpotDiagnosticMXBean diagnosticBean = ManagementFactory.getPlatformMXBean(
HotSpotDiagnosticMXBean.class);
diagnosticBean.dumpHeap(fileName, true);
System.out.println("Heap dump generated: " + fileName);
return true;
} catch (Exception e) {
System.err.println("Failed to generate heap dump: " + e.getMessage());
return false;
}
}

8. Usage Examples and Main Class

    /**
* Example usage and main class
*/
public static class MemoryLeakDetectorDemo {
public static void main(String[] args) {
// Configure and create detector
MemoryLeakDetector detector = DetectorConfig.builder()
.checkIntervalMs(3000)
.memoryThresholdPercent(80)
.maxSnapshots(30)
.listener(new LoggingMemoryLeakListener("[Demo]"))
.build();
// Start monitoring
detector.startMonitoring();
// Simulate some memory usage
simulateMemoryUsage();
// Wait for monitoring
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// Perform analysis
LeakAnalysisResult result = detector.analyzePotentialLeaks();
System.out.println(result.generateDetailedReport());
// Generate report
try {
detector.getReportGenerator().generateReport(detector, "memory-leak-report.html");
} catch (IOException e) {
System.err.println("Failed to generate report: " + e.getMessage());
}
// Stop monitoring
detector.stopMonitoring();
}
private static void simulateMemoryUsage() {
// Create some objects to simulate memory usage
List<byte[]> dataList = new ArrayList<>();
for (int i = 0; i < 100; i++) {
dataList.add(new byte[1024 * 1024]); // 1MB each
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
}
}
public LeakReportGenerator getReportGenerator() {
return reportGenerator;
}
}
// Utility class for system output
class System {
public static void info(String message) {
java.lang.System.out.println("[INFO] " + message);
}
public static void warn(String message) {
java.lang.System.out.println("[WARN] " + message);
}
public static void error(String message) {
java.lang.System.err.println("[ERROR] " + message);
}
}

Features

  • Real-time Monitoring: Continuous memory usage tracking
  • Automatic Snapshots: Periodic memory state capture
  • Leak Detection: Pattern-based leak identification
  • Trend Analysis: Memory growth trend detection
  • Detailed Reporting: HTML and text reports
  • GC Monitoring: Garbage collection effectiveness analysis
  • Configurable: Customizable thresholds and intervals
  • Non-intrusive: Low performance overhead

Usage Examples

Basic Usage

MemoryLeakDetector detector = new MemoryLeakDetector();
detector.startMonitoring();
// Your application code here
LeakAnalysisResult result = detector.analyzePotentialLeaks();
System.out.println(result.getSummary());

Advanced Configuration

MemoryLeakDetector detector = MemoryLeakDetector.DetectorConfig.builder()
.checkIntervalMs(2000)
.memoryThresholdPercent(75)
.listener(new LoggingMemoryLeakListener("[MyApp]"))
.build();

This memory leak detector provides comprehensive monitoring and analysis capabilities to help identify and diagnose memory issues in Java applications.

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper