google-site-verification: google61fe8ba583a51912.html
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