-
Notifications
You must be signed in to change notification settings - Fork 93
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fixed slow memory-leak by replacing WeakHashMap with SoftHashMap<...,…
…TickMark> - based cache implementation See following references for details: https://ewirch.github.io/2013/12/weakhashmap-memory-leaks.html https://franke.ms/memoryleak1.wiki N.B. latter author filed this as a bug at http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7145759 which was apparently dropped by Oracle devs as supposedly the intended behaviour for a WeakHashMap-based cache.
- Loading branch information
1 parent
eb7a286
commit 17a4ac1
Showing
4 changed files
with
111 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
83 changes: 83 additions & 0 deletions
83
chartfx-chart/src/test/java/de/gsi/chart/axes/spi/MemoryLeakTestDefaultAxis.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package de.gsi.chart.axes.spi; | ||
|
||
import java.util.Map; | ||
import java.util.Timer; | ||
import java.util.TimerTask; | ||
|
||
import javafx.application.Application; | ||
import javafx.application.Platform; | ||
import javafx.geometry.Insets; | ||
import javafx.scene.Scene; | ||
import javafx.scene.layout.Priority; | ||
import javafx.scene.layout.VBox; | ||
import javafx.stage.Stage; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import de.gsi.chart.utils.FXUtils; | ||
|
||
/** | ||
* Small test to demonstrate that the SoftHashMap TickMark cache sizes are in fact limited, memory-bound and do not leak | ||
* rather than their earlier WeakHashMap-based counterpart that had issues when the weak key was also part of the kept value. | ||
* | ||
* See following references for details: | ||
* https://ewirch.github.io/2013/12/weakhashmap-memory-leaks.html | ||
* https://franke.ms/memoryleak1.wiki | ||
* N.B. latter author filed this as a bug at http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7145759 which was apparently | ||
* dropped by Oracle devs as supposedly the intended behaviour for a WeakHashMap-based cache. | ||
* | ||
* effect is best seen with limiting the jvm's max memory: -Xmx20m | ||
* | ||
* @author rstein | ||
*/ | ||
public class MemoryLeakTestDefaultAxis extends Application { | ||
private static final Logger LOGGER = LoggerFactory.getLogger(MemoryLeakTestDefaultAxis.class); | ||
@Override | ||
public void start(final Stage primaryStage) { | ||
final TestAxis axis = new TestAxis(); | ||
VBox.setMargin(axis, new Insets(5, 50, 5, 50)); | ||
VBox.setVgrow(axis, Priority.ALWAYS); | ||
|
||
new Timer(true).scheduleAtFixedRate(new TimerTask() { | ||
private int counter; | ||
@Override | ||
public void run() { | ||
FXUtils.runFX(() -> axis.set(now(), now() + 1)); | ||
if (counter % 5000 == 0) { | ||
LOGGER.atInfo().addArgument(axis.getTickMarkDoubleCache().size()).addArgument(axis.getTickMarkStringCache().size()).log("cache sizes - Map<Double,TickMark> = {} Map<String,TickMark> = {}"); | ||
System.gc(); // NOPMD NOSONAR - yes we need to eliminate the non-deterministic behaviour of the jvm's gc | ||
System.gc(); // NOPMD NOSONAR - yes we need to eliminate the non-deterministic behaviour of the jvm's gc | ||
} | ||
counter++; | ||
} | ||
}, 0, 1); | ||
|
||
primaryStage.setTitle(this.getClass().getSimpleName()); | ||
primaryStage.setScene(new Scene(new VBox(axis), 1800, 100)); | ||
primaryStage.setOnCloseRequest(evt -> Platform.exit()); | ||
primaryStage.show(); | ||
} | ||
|
||
public static void main(final String[] args) { | ||
Application.launch(args); | ||
} | ||
|
||
private static double now() { | ||
return 0.001 * System.currentTimeMillis(); // [s] | ||
} | ||
|
||
private class TestAxis extends DefaultNumericAxis { | ||
public TestAxis() { | ||
super("test axis", now(), now() + 1, 0.05); | ||
} | ||
|
||
public Map<Double, TickMark> getTickMarkDoubleCache() { | ||
return tickMarkDoubleCache; | ||
} | ||
|
||
public Map<String, TickMark> getTickMarkStringCache() { | ||
return tickMarkStringCache; | ||
} | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
chartfx-chart/src/test/java/de/gsi/chart/axes/spi/MemoryLeakTestDefaultAxis_run.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package de.gsi.chart.axes.spi; | ||
|
||
import javafx.application.Application; | ||
|
||
/** | ||
* Small test to demonstrate that the SoftHashMap TickMark cache sizes are in fact limited, memory-bound and do not leak | ||
* rather than their earlier WeakHashMap-based counterpart that had issues when the weak key was also part of the kept value. | ||
* | ||
* See following references for details: | ||
* https://ewirch.github.io/2013/12/weakhashmap-memory-leaks.html | ||
* https://franke.ms/memoryleak1.wiki | ||
* N.B. latter author filed this as a bug at http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7145759 which was apparently | ||
* dropped by Oracle devs as supposedly the intended behaviour for a WeakHashMap-based cache. | ||
* | ||
* effect is best seen with limiting the jvm's max memory: -Xmx20m | ||
* | ||
* @author rstein | ||
*/ | ||
public class MemoryLeakTestDefaultAxis_run { | ||
public static void main(final String[] args) { | ||
Application.launch(MemoryLeakTestDefaultAxis.class); | ||
} | ||
} |