Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,38 @@ public static void nativeMemoryLeakCheck() throws Exception {
}
}

/**
* Checks for JVM memory leaks by comparing memory usage before and after test.
* A significant increase in memory usage indicates a potential leak.
*
* @param memoryBeforeTest The JVM memory usage before the test started
* @throws Exception if a memory leak is detected
*/
public static void jvmMemoryLeakCheck(long memoryBeforeTest) throws Exception {
long memoryAfterTest = getJvmMemoryInUse();
long memoryGrowth = memoryAfterTest - memoryBeforeTest;

// Allow some tolerance for normal memory fluctuations (5MB)
long maxAllowedGrowth = expectedFixedGrowth();

if (memoryGrowth > maxAllowedGrowth) {
String output = String.format(
"Potential JVM Memory Leak Detected!\n" +
"Memory before test: %d bytes (%.2f MB)\n" +
"Memory after test: %d bytes (%.2f MB)\n" +
"Memory growth: %d bytes (%.2f MB)\n" +
"Allowed growth: %d bytes (%.2f MB)\n",
memoryBeforeTest, memoryBeforeTest / (1024.0 * 1024.0),
memoryAfterTest, memoryAfterTest / (1024.0 * 1024.0),
memoryGrowth, memoryGrowth / (1024.0 * 1024.0),
maxAllowedGrowth, maxAllowedGrowth / (1024.0 * 1024.0)
);

Log.log(Log.LogLevel.Error, Log.LogSubject.JavaCrtGeneral, output);
Assert.fail(output);
}
}

public static void leakCheck(Callable<Void> fn) throws Exception {
leakCheck(DEFAULT_NUM_LEAK_TEST_ITERATIONS, expectedFixedGrowth(), fn);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
public class CrtTestFixture {

private CrtTestContext context;
private long jvmMemoryBeforeTest;

@Rule
public TestName testName = new TestName();
Expand Down Expand Up @@ -239,6 +240,13 @@ public void setup() {
System.out.println("[TEST START] " + testName.getMethodName());
Log.log(Log.LogLevel.Debug, LogSubject.JavaCrtGeneral, "CrtTestFixture setup begin");

// Capture initial JVM memory usage for leak detection
if (CRT.getOSIdentifier() != "android") {
// Force GC to get a stable baseline
Runtime.getRuntime().gc();
jvmMemoryBeforeTest = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
}

// TODO this CrtTestContext should be removed as we are using System Properties
// for tests now.
context = new CrtTestContext();
Expand All @@ -260,8 +268,9 @@ public void tearDown() {
try {
Runtime.getRuntime().gc();
CrtMemoryLeakDetector.nativeMemoryLeakCheck();
CrtMemoryLeakDetector.jvmMemoryLeakCheck(jvmMemoryBeforeTest);
} catch (Exception e) {
throw new RuntimeException("Memory leak from native resource detected!");
throw new RuntimeException("Memory leak detected!");
}
}
Log.log(Log.LogLevel.Debug, LogSubject.JavaCrtGeneral, "CrtTestFixture tearDown end");
Expand Down
Loading