If we take a look deeper into implementation, we will see that every placeholder request, simply creating new object of the engine which is generally unnecessary and destructive to GC.
Current code doing smth like that (nashorn):
import javax.script.ScriptException;
import org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory;
public class Leak {
public static void main(String[] args) throws ScriptException {
var factory = new NashornScriptEngineFactory();
while (true) {
var engine = factory.getScriptEngine("--no-java");
System.out.printf("Result: %s\n", engine.eval("1 + 1"));
}
}
}
let's dump our little application and we will see that jdk.internal.ref.CleanerImpl$PhantomCleanableRef top consumer, when in NORMAL application, byte[] most time is top consumer. That's point on memory leak.
If you still doesn't believe, you can just dump via jmap and analyse it via Eclipse Memory Analyzer (https://www.eclipse.org/mat/)
Possible solutions? Do not create for each execution new engine/context
If we take a look deeper into implementation, we will see that every placeholder request, simply creating new object of the engine which is generally unnecessary and destructive to GC.
Current code doing smth like that (nashorn):
if we take a look at
getScriptEngine
(https://github.com/openjdk/nashorn/blob/ab2542ea0f3decad033991916167dbce4a46f314/src/org.openjdk.nashorn/share/classes/org/openjdk/nashorn/api/scripting/NashornScriptEngineFactory.java#L233), we will see that it's create all the time new object, when we can just use oneScriptEngine
for everything, simply rebinding all needed variables.let's dump our little application and we will see that
jdk.internal.ref.CleanerImpl$PhantomCleanableRef
top consumer, when in NORMAL application,byte[]
most time is top consumer. That's point on memory leak.If you still doesn't believe, you can just dump via
jmap
and analyse it via Eclipse Memory Analyzer (https://www.eclipse.org/mat/)Possible solutions? Do not create for each execution new engine/context