Skip to content

Commit

Permalink
Some project gradle restructure and general cleanup (#7)
Browse files Browse the repository at this point in the history
* Move some gradle project constants under `gradle.properties` file

* Enable JUnit 5 tests in Gradle

* Run tests in GitHub CI builds

* Set project minimal Java source and target compatibility to version `11`

* Parametrize types for classes and methods

* Replace with 'Comparator.comparing'

* Use wildcard `?` to accept any type in the used set

* Some code formatting and cleanup

* Delete unused markdown file

* Cleanup `build.gradle`

* Update changelog

* Remove parametrization from the `JMemoryBuddy#memoryTest` method

* Remove parametrization from other classes and methods
  • Loading branch information
besidev authored Jul 11, 2024
1 parent 3f3acc6 commit 4a33fa5
Show file tree
Hide file tree
Showing 12 changed files with 120 additions and 107 deletions.
20 changes: 0 additions & 20 deletions .github/workflows/gradle.yml

This file was deleted.

24 changes: 24 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
name: Build CI

on: [push]

jobs:
build:
strategy:
matrix:
jdk: [11, 17, 21]

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '${{matrix.jdk}}'

- name: Build with Gradle
run: ./gradlew build

- name: Run tests
run: ./gradlew test
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
### 0.5.5
* Parameterize classes and methods providing better type safety
* Set minimum Java version to 11
* Enable JUnit 5 tests running in the CI builds

### 0.5.4
* Slightly improved error messages
* Updated CI to use also use Java17 and Java21
Expand Down
3 changes: 0 additions & 3 deletions JMemoryBuddy.md

This file was deleted.

28 changes: 16 additions & 12 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,10 @@ buildscript {
repositories {
mavenCentral()
}

}

plugins {
id "io.github.gradle-nexus.publish-plugin" version "1.3.0"
id "io.github.gradle-nexus.publish-plugin" version "$NEXUS_PUBLISH_PLUGIN_VERSION"
}

repositories {
Expand All @@ -19,30 +18,35 @@ apply plugin: 'signing'


group = 'de.sandec'
archivesBaseName = "JMemoryBuddy"
version = '0.5.4'

sourceCompatibility = 8
targetCompatibility = 8
archivesBaseName = "$ARCHIVE_BASE_NAME"
version = "$JMEMORYBUDDY_VERSION"

java {
sourceCompatibility = 11
targetCompatibility = 11

withSourcesJar()
withJavadocJar()
}

dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
//implementation 'org.openjdk.jol:jol-core:0.17'
testImplementation "org.junit.jupiter:junit-jupiter:$JUNIT_VERSION"
testImplementation "org.junit.jupiter:junit-jupiter-api:$JUNIT_VERSION"
testImplementation "org.junit.jupiter:junit-jupiter-params:$JUNIT_VERSION"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$JUNIT_VERSION"
testRuntimeOnly "ch.qos.logback:logback-classic:$LOGBACK_VERSION"
}

test {
useJUnitPlatform()
}

test {
testLogging {
events "passed", "skipped", "failed"
showStandardStreams = true
showExceptions true
showCauses true
showStackTraces true
exceptionFormat "full"
}
}

Expand Down
6 changes: 6 additions & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
JMEMORYBUDDY_VERSION=0.5.5-SNAPSHOT
ARCHIVE_BASE_NAME=JMemoryBuddy

NEXUS_PUBLISH_PLUGIN_VERSION=1.3.0
JUNIT_VERSION=5.10.3
LOGBACK_VERSION=1.5.6
23 changes: 13 additions & 10 deletions src/main/java/de/sandec/jmemorybuddy/CleanupDetector.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
package de.sandec.jmemorybuddy;

import java.lang.ref.WeakReference;
import java.lang.ref.ReferenceQueue;
import java.util.HashSet;
import java.lang.ref.WeakReference;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class CleanupDetector {

private static HashSet<WeakReferenceWithRunnable> references = new HashSet<WeakReferenceWithRunnable>();
private static ReferenceQueue queue = new ReferenceQueue();;
private static final Set<WeakReferenceWithRunnable> references = ConcurrentHashMap.newKeySet();
private static final ReferenceQueue<Object> queue = new ReferenceQueue<>();

static {
Thread cleanupDetectorThread = new Thread(() -> {
Expand All @@ -29,21 +30,23 @@ public class CleanupDetector {
* The runnable gets executed after the object has been collected by the GC.
*/
public static void onCleanup(Object obj, Runnable r) {
onCleanup(new WeakReferenceWithRunnable(obj,r));
onCleanup(new WeakReferenceWithRunnable(obj, r));
}

/**
* This version of the method can be used to provide more information
* This version of the method can be used to provide more information
* in the heap dump by extending WeakReferenceWithRunnable.
*/
public static void onCleanup(WeakReferenceWithRunnable weakref) {
references.add(weakref);
public static void onCleanup(WeakReferenceWithRunnable weakRef) {
references.add(weakRef);
}

/**
* This class can be extended to provide more meta information to the method onCleanup.
*/
public static class WeakReferenceWithRunnable extends WeakReference {
Runnable r = null;
public static class WeakReferenceWithRunnable extends WeakReference<Object> {
Runnable r;

WeakReferenceWithRunnable(Object ref, Runnable r) {
super(ref, queue);
this.r = r;
Expand Down
76 changes: 37 additions & 39 deletions src/main/java/de/sandec/jmemorybuddy/JMemoryBuddy.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package de.sandec.jmemorybuddy;

import com.sun.management.HotSpotDiagnosticMXBean;

import javax.management.MBeanServer;
import java.io.File;
import java.io.IOException;
Expand All @@ -11,8 +12,6 @@
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.
Expand All @@ -21,11 +20,11 @@
*/
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 final int steps;
private static final int testDuration;
private static final int sleepDuration;
private static final boolean createHeapdump;
private static final int garbageAmount;
private static String mxBeanProxyName = "com.sun.management:type=HotSpotDiagnostic";
private static String outputFolderString = ".";

Expand All @@ -49,7 +48,7 @@ private static String getDefaultOutputFolder() {
}

static void createGarbage() {
LinkedList list = new LinkedList<Integer>();
LinkedList<Integer> list = new LinkedList<>();
int counter = 0;
while (counter < garbageAmount) {
counter += 1;
Expand All @@ -61,7 +60,7 @@ static void createGarbage() {
* Checks whether the content of the WeakReference can be collected.
* @param weakReference The WeakReference to check.
*/
public static void assertCollectable(WeakReference weakReference) {
public static void assertCollectable(WeakReference<?> weakReference) {
if (!checkCollectable(weakReference)) {
AssertCollectable assertCollectable = new AssertCollectable(weakReference);
createHeapDump();
Expand All @@ -74,11 +73,11 @@ public static void assertCollectable(WeakReference weakReference) {
* @param weakReference The WeakReference to check.
* @return Returns true, when the provided WeakReference can be collected.
*/
public static boolean checkCollectable(WeakReference weakReference) {
public static boolean checkCollectable(WeakReference<?> weakReference) {
return checkCollectable(steps, weakReference) > 0;
}

private static int checkCollectable(int stepsLeft, WeakReference weakReference) {
private static int checkCollectable(int stepsLeft, WeakReference<?> weakReference) {
int counter = stepsLeft;

if (weakReference.get() != null) {
Expand All @@ -100,7 +99,7 @@ private static int checkCollectable(int stepsLeft, WeakReference weakReference)
}

if (weakReference.get() == null && counter < steps / 3) {
int percentageUsed = (int) ((steps - counter) / steps * 100);
int percentageUsed = (steps - counter) / steps * 100;
System.out.println("Warning test seems to be unstable. time used: " + percentageUsed + "%");
}

Expand All @@ -111,7 +110,7 @@ private static int checkCollectable(int stepsLeft, WeakReference weakReference)
* Checks whether the content of the WeakReference cannot be collected.
* @param weakReference The WeakReference to check.
*/
public static void assertNotCollectable(WeakReference weakReference) {
public static void assertNotCollectable(WeakReference<Object> weakReference) {
if (!checkNotCollectable(weakReference)) {
throw new AssertionError("Content of WeakReference was collected!");
}
Expand All @@ -122,7 +121,7 @@ public static void assertNotCollectable(WeakReference weakReference) {
* @param weakReference The WeakReference to check.
* @return Returns true, when the provided WeakReference cannot be collected.
*/
public static boolean checkNotCollectable(WeakReference weakReference) {
public static boolean checkNotCollectable(WeakReference<?> weakReference) {
createGarbage();
System.gc();
System.runFinalization();
Expand All @@ -134,17 +133,17 @@ public static boolean checkNotCollectable(WeakReference weakReference) {
/**
* 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.
* @param f A function which gets executed with the API to define the required memory semantic.
*/
public static void memoryTest(Consumer<MemoryTestAPI> f) {
LinkedList<WeakReference> toBeCollected = new LinkedList<WeakReference>();
LinkedList<AssertNotCollectable> toBeNotCollected = new LinkedList<AssertNotCollectable>();
LinkedList<SetAsReferenced> toBeReferenced = new LinkedList<SetAsReferenced>();
LinkedList<WeakReference<?>> toBeCollected = new LinkedList<>();
LinkedList<AssertNotCollectable> toBeNotCollected = new LinkedList<>();
LinkedList<SetAsReferenced> toBeReferenced = new LinkedList<>();

f.accept(new MemoryTestAPI() {
public void assertCollectable(Object ref) {
Objects.requireNonNull(ref);
toBeCollected.add(new WeakReference<Object>(ref));
toBeCollected.add(new WeakReference<>(ref));
}
public void assertNotCollectable(Object ref) {
Objects.requireNonNull(ref);
Expand All @@ -159,7 +158,7 @@ public void setAsReferenced(Object ref) {
int stepsLeft = steps;
boolean failed = false;

for (WeakReference wRef: toBeCollected) {
for (WeakReference<?> wRef: toBeCollected) {
stepsLeft = checkCollectable(stepsLeft, wRef);
}
if (stepsLeft == 0) {
Expand All @@ -172,10 +171,10 @@ public void setAsReferenced(Object ref) {
}

if (failed) {
LinkedList<AssertCollectable> toBeCollectedMarked = new LinkedList<AssertCollectable>();
LinkedList<AssertNotCollectable> toBeNotCollectedMarked = new LinkedList<AssertNotCollectable>();
LinkedList<AssertCollectable> toBeCollectedMarked = new LinkedList<>();
LinkedList<AssertNotCollectable> toBeNotCollectedMarked = new LinkedList<>();

for (WeakReference wRef: toBeCollected) {
for (WeakReference<?> wRef: toBeCollected) {
if (wRef.get() != null) {
toBeCollectedMarked.add(new AssertCollectable(wRef));
}
Expand Down Expand Up @@ -219,43 +218,43 @@ private static void setMxBeanProxyName(String mxBeanName) {

private static HotSpotDiagnosticMXBean getHotspotMBean() throws IOException {
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
HotSpotDiagnosticMXBean bean =
ManagementFactory.newPlatformMXBeanProxy(server,
mxBeanProxyName, HotSpotDiagnosticMXBean.class);
return bean;
return ManagementFactory.newPlatformMXBeanProxy(server,
mxBeanProxyName, HotSpotDiagnosticMXBean.class);
}

/**
* This class provides different methods, which can be used to declare memory-constraints.
* You can get an instance through the lambda of the method JMemoryBuddy.memoryTest.
*/
public static interface MemoryTestAPI {
public interface MemoryTestAPI {

/**
* After executing the lambda, the provided ref must be collectable. Otherwise an Exception is thrown.
* After executing the lambda, the provided ref must be collectable. Otherwise, an Exception is thrown.
* @param ref The reference which should be collectable.
*/
public void assertCollectable(Object ref);
void assertCollectable(Object ref);

/**
* After executing the lambda, the provided ref must be not collectable. Otherwise an Exception is thrown.
* After executing the lambda, the provided ref must be not collectable. Otherwise, an Exception is thrown.
* @param ref The reference which should not be collectable.
*/
public void assertNotCollectable(Object ref);
void assertNotCollectable(Object ref);

/**
* The provided reference will be reference hard, so it won't be collected, until memoryTest finishes.
* @param ref The reference which should get a hard reference for this test.
*/
public void setAsReferenced(Object ref);
void setAsReferenced(Object ref);
}

static class AssertCollectable {
WeakReference<Object> assertCollectable;
WeakReference<?> assertCollectable;

AssertCollectable(WeakReference<Object> ref) {
AssertCollectable(WeakReference<?> ref) {
this.assertCollectable = ref;
}

WeakReference<Object> getWeakReference() {
WeakReference<?> getWeakReference() {
return assertCollectable;
}

Expand All @@ -267,15 +266,15 @@ public String toString() {
}

private static class AssertNotCollectable {
WeakReference<Object> assertNotCollectable;
WeakReference<?> assertNotCollectable;
String originalResultOfToString;

AssertNotCollectable(Object ref) {
this.assertNotCollectable = new WeakReference<>(ref);
originalResultOfToString = ref.toString();
}

WeakReference<Object> getWeakReference() {
WeakReference<?> getWeakReference() {
return assertNotCollectable;
}

Expand All @@ -292,5 +291,4 @@ private static class SetAsReferenced {
this.setAsReferenced = ref;
}
}

}
Loading

0 comments on commit 4a33fa5

Please sign in to comment.