de.sandec.jmemorybuddy.JMemoryBuddy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of JMemoryBuddy Show documentation
Show all versions of JMemoryBuddy Show documentation
A library usefull for unit testing memory leaks
package de.sandec.jmemorybuddy;
import com.sun.management.HotSpotDiagnosticMXBean;
import javax.management.MBeanServer;
import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.ref.WeakReference;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedList;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* JMemoryBuddy provides various methods to test for memory leaks.
* It makes it easy to verify the memory behavior in a unit test ensuring the stability and quality of your code.
* Checkout https://github.com/Sandec/JMemoryBuddy for more documentation.
*/
public class JMemoryBuddy {
private static int steps;
private static int testDuration;
private static int sleepDuration;
private static boolean createHeapdump;
private static int garbageAmount = 999999;
private static String mxBeanProxyName = "com.sun.management:type=HotSpotDiagnostic";
private static String outputFolderString = ".";
static {
outputFolderString = System.getProperty("jmemorybuddy.output", getDefaultOutputFolder());
testDuration = Integer.parseInt(System.getProperty("jmemorybuddy.testDuration","1000"));
steps = Integer.parseInt(System.getProperty("jmemorybuddy.steps", "10"));
createHeapdump = Boolean.parseBoolean(System.getProperty("jmemorybuddy.createHeapdump", "true"));
garbageAmount = Integer.parseInt(System.getProperty("jmemorybuddy.garbageAmount", "99999"));
sleepDuration = testDuration / steps;
}
private static String getDefaultOutputFolder() {
File folder1 = new File("target");
File folder2 = new File("build");
if (folder1.exists()) return folder1.getAbsolutePath();
if (folder2.exists()) return folder2.getAbsolutePath();
return ".";
}
static void createGarbage() {
LinkedList list = new LinkedList();
int counter = 0;
while (counter < garbageAmount) {
counter += 1;
list.add(1);
}
}
/**
* Checks whether the content of the WeakReference can be collected.
* @param weakReference The WeakReference to check.
*/
public static void assertCollectable(WeakReference weakReference) {
if (!checkCollectable(weakReference)) {
AssertCollectable assertCollectable = new AssertCollectable(weakReference);
createHeapDump();
throw new AssertionError("Content of WeakReference was not collected. content: " + weakReference.get());
}
}
/**
* Checks whether the content of the WeakReference can be collected.
* @param weakReference The WeakReference to check.
* @return Returns true, when the provided WeakReference can be collected.
*/
public static boolean checkCollectable(WeakReference weakReference) {
return checkCollectable(steps, weakReference) > 0;
}
private static int checkCollectable(int stepsLeft, WeakReference weakReference) {
int counter = stepsLeft;
if (weakReference.get() != null) {
createGarbage();
System.gc();
System.runFinalization();
}
while (counter > 0 && weakReference.get() != null) {
try {
Thread.sleep(sleepDuration);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
counter = counter - 1;
createGarbage();
System.gc();
System.runFinalization();
}
if (weakReference.get() == null && counter < steps / 3) {
int percentageUsed = (int) ((steps - counter) / steps * 100);
System.out.println("Warning test seems to be unstable. time used: " + percentageUsed + "%");
}
return counter;
}
/**
* Checks whether the content of the WeakReference cannot be collected.
* @param weakReference The WeakReference to check.
*/
public static void assertNotCollectable(WeakReference weakReference) {
if (!checkNotCollectable(weakReference)) {
throw new AssertionError("Content of WeakReference was collected!");
}
}
/**
* Checks whether the content of the WeakReference cannot be collected.
* @param weakReference The WeakReference to check.
* @return Returns true, when the provided WeakReference cannot be collected.
*/
public static boolean checkNotCollectable(WeakReference weakReference) {
createGarbage();
System.gc();
System.runFinalization();
createGarbage();
System.gc();
return weakReference.get() != null;
}
/**
* A standard method to define a test which checks code for specific memory semantic.
* The parameter of the lambda provides an API to define the required memory semantic.
* @param f A function which get's executed with the API to define the required memory semantic.
*/
public static void memoryTest(Consumer f) {
LinkedList toBeCollected = new LinkedList();
LinkedList toBeNotCollected = new LinkedList();
LinkedList toBeReferenced = new LinkedList();
f.accept(new MemoryTestAPI() {
public void assertCollectable(Object ref) {
Objects.requireNonNull(ref);
toBeCollected.add(new WeakReference