Skip to content

Commit 1f8826d

Browse files
committed
JythonBindings: don't store engine or module
If the JythonScriptEngine or containing ScriptModule is set within the PythonInterpreter, we will get a circular reference chain preventing memory from the PythonInterpreter being reclaimed. To avoid completely discarding these objects, we can keep them in a shallow map to WeakReferences.
1 parent 0444100 commit 1f8826d

File tree

1 file changed

+25
-5
lines changed

1 file changed

+25
-5
lines changed

src/main/java/org/scijava/plugins/scripting/jython/JythonBindings.java

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@
3131

3232
package org.scijava.plugins.scripting.jython;
3333

34+
import java.lang.ref.WeakReference;
3435
import java.util.ArrayList;
3536
import java.util.Collection;
37+
import java.util.HashMap;
3638
import java.util.HashSet;
3739
import java.util.List;
3840
import java.util.Map;
@@ -42,6 +44,7 @@
4244

4345
import org.python.core.PyStringMap;
4446
import org.python.util.PythonInterpreter;
47+
import org.scijava.script.ScriptModule;
4548

4649
/**
4750
* A {@link Bindings} wrapper around Jython's local variables.
@@ -52,6 +55,9 @@ public class JythonBindings implements Bindings {
5255

5356
protected final PythonInterpreter interpreter;
5457

58+
private Map<String, WeakReference<Object>> shallowMap =
59+
new HashMap<String, WeakReference<Object>>();
60+
5561
public JythonBindings(final PythonInterpreter interpreter) {
5662
this.interpreter = interpreter;
5763
}
@@ -81,6 +87,10 @@ public boolean containsValue(Object value) {
8187

8288
@Override
8389
public Object get(Object key) {
90+
if (shallowMap.containsKey(key)) {
91+
return shallowMap.get(key).get();
92+
}
93+
8494
try {
8595
return interpreter.get((String)key);
8696
} catch (Error e) {
@@ -91,18 +101,28 @@ public Object get(Object key) {
91101
@Override
92102
public Object put(String key, Object value) {
93103
final Object result = get(key);
94-
try {
95-
interpreter.set(key, value);
96-
} catch (Error e) {
97-
// ignore
104+
105+
if (value instanceof ScriptModule || value instanceof JythonScriptEngine){
106+
shallowMap.put(key, new WeakReference<Object>(value));
107+
}
108+
else {
109+
try {
110+
interpreter.set(key, value);
111+
}
112+
catch (Error e) {
113+
// ignore
114+
}
98115
}
116+
99117
return result;
100118
}
101119

102120
@Override
103121
public Object remove(Object key) {
104122
final Object result = get(key);
105-
if (result != null) interpreter.getLocals().__delitem__((String)key);
123+
if (shallowMap.containsKey(key)) shallowMap.remove(key);
124+
else if (result != null) interpreter.getLocals().__delitem__((String)key);
125+
106126
return result;
107127
}
108128

0 commit comments

Comments
 (0)