Skip to content

Commit aa0a1f5

Browse files
authored
Merge pull request #823 from MarcMil/improve-code
Fix lingering reference by MemoryWatcher
2 parents 38a64fe + 786706c commit aa0a1f5

File tree

2 files changed

+81
-51
lines changed

2 files changed

+81
-51
lines changed

soot-infoflow/src/soot/jimple/infoflow/memory/MemoryWarningSystem.java

Lines changed: 7 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,9 @@ public interface OnMemoryThresholdReached {
6666
private final static NotificationListener memoryListener;
6767
private boolean isClosed = false;
6868

69-
private long threshold;
69+
long threshold;
7070

71-
private static Thread thrLowMemoryWarningThread;
71+
static Thread thrLowMemoryWarningThread;
7272

7373
private static TreeSet<MemoryWarningSystem> warningSystems = new TreeSet<>(new Comparator<MemoryWarningSystem>() {
7474

@@ -103,7 +103,7 @@ public boolean isNotificationEnabled(Notification notification) {
103103

104104
}
105105

106-
private static long triggerNotification() {
106+
static long triggerNotification() {
107107
long maxMemory = tenuredGenPool.getUsage().getMax();
108108
long usedMemory = tenuredGenPool.getUsage().getUsed();
109109

@@ -206,54 +206,9 @@ public void setWarningThreshold(double percentage) {
206206
if (useOwnImplementation) {
207207
// No JVM support is available, use our own implementation
208208
if (thrLowMemoryWarningThread == null) {
209-
thrLowMemoryWarningThread = ThreadUtils.createGenericThread(new Runnable() {
210-
211-
@Override
212-
public void run() {
213-
while (true) {
214-
MemoryWarningSystem l;
215-
synchronized (warningSystems) {
216-
if (warningSystems.isEmpty()) {
217-
thrLowMemoryWarningThread = null;
218-
return;
219-
}
220-
l = warningSystems.iterator().next();
221-
}
222-
long nextThreshold = l.threshold;
223-
MemoryUsage usage = tenuredGenPool.getUsage();
224-
if (usage == null) {
225-
logger.warn(MessageFormat.format("Memory usage of {0} could not be estimated",
226-
tenuredGenPool.getName()));
227-
return;
228-
} else {
229-
long used = usage.getUsed();
230-
if (used >= l.threshold) {
231-
nextThreshold = triggerNotification();
232-
if (nextThreshold == -1) {
233-
synchronized (warningSystems) {
234-
if (warningSystems.isEmpty()) {
235-
thrLowMemoryWarningThread = null;
236-
return;
237-
}
238-
}
239-
}
240-
}
241-
}
242-
long used = usage.getUsed();
243-
// Depending on how far we are from the next threshold, we can rest longer
244-
// or shorter
245-
long missing = nextThreshold - used;
246-
if (missing <= 0)
247-
continue;
248-
try {
249-
long wait = (long) ((missing / (double) tenuredGenPool.getUsage().getMax()) * 500);
250-
Thread.sleep(wait);
251-
} catch (InterruptedException e) {
252-
}
253-
}
254-
}
255-
256-
}, "Low memory monitor", true);
209+
thrLowMemoryWarningThread = ThreadUtils.createGenericThread(
210+
new MemoryWarningThreadRunnable(tenuredGenPool, warningSystems, logger),
211+
"Low memory monitor", true);
257212
thrLowMemoryWarningThread.setPriority(Thread.MIN_PRIORITY);
258213
thrLowMemoryWarningThread.start();
259214
}
@@ -281,6 +236,7 @@ public void close() {
281236
// Doesn't matter, we wanted to get rid of it anyway
282237
}
283238
isClosed = true;
239+
listeners.clear();
284240
}
285241

286242
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package soot.jimple.infoflow.memory;
2+
3+
import java.lang.management.MemoryPoolMXBean;
4+
import java.lang.management.MemoryUsage;
5+
import java.text.MessageFormat;
6+
import java.util.TreeSet;
7+
8+
import org.slf4j.Logger;
9+
10+
/**
11+
* We made this class separate to ensure that there is no direct connection to a concrete instance
12+
* of a MemoryWarningSystem, since this runner runs independently from all instances.
13+
*/
14+
final class MemoryWarningThreadRunnable implements Runnable {
15+
16+
private MemoryPoolMXBean tenuredGenPool;
17+
private TreeSet<MemoryWarningSystem> warningSystems;
18+
private Logger logger;
19+
20+
public MemoryWarningThreadRunnable(MemoryPoolMXBean tenuredgenpool, TreeSet<MemoryWarningSystem> warningSystems,
21+
Logger logger) {
22+
this.tenuredGenPool = tenuredgenpool;
23+
this.warningSystems = warningSystems;
24+
this.logger = logger;
25+
}
26+
27+
@Override
28+
public void run() {
29+
try {
30+
while (true) {
31+
MemoryWarningSystem l;
32+
synchronized (warningSystems) {
33+
if (warningSystems.isEmpty()) {
34+
return;
35+
}
36+
l = warningSystems.iterator().next();
37+
}
38+
long nextThreshold = l.threshold;
39+
MemoryUsage usage = tenuredGenPool.getUsage();
40+
if (usage == null) {
41+
logger.warn(MessageFormat.format("Memory usage of {0} could not be estimated",
42+
tenuredGenPool.getName()));
43+
return;
44+
} else {
45+
long used = usage.getUsed();
46+
if (used >= l.threshold) {
47+
nextThreshold = MemoryWarningSystem.triggerNotification();
48+
if (nextThreshold == -1) {
49+
synchronized (warningSystems) {
50+
if (warningSystems.isEmpty()) {
51+
return;
52+
}
53+
}
54+
}
55+
}
56+
}
57+
long used = usage.getUsed();
58+
// Depending on how far we are from the next threshold, we can rest longer
59+
// or shorter
60+
long missing = nextThreshold - used;
61+
if (missing <= 0)
62+
continue;
63+
try {
64+
long wait = (long) ((missing / (double) tenuredGenPool.getUsage().getMax()) * 500);
65+
Thread.sleep(wait);
66+
} catch (InterruptedException e) {
67+
}
68+
}
69+
} finally {
70+
MemoryWarningSystem.thrLowMemoryWarningThread = null;
71+
}
72+
}
73+
74+
}

0 commit comments

Comments
 (0)