FULL PRODUCT VERSION :
java version "1.8.0_144"
Java(TM) SE Runtime Environment (build 1.8.0_144-b01)
Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux 2.6.32-042stab117.16
OS X 10.13.3
A DESCRIPTION OF THE PROBLEM :
When I configure spark-java application from JavaScript and run this code from Tomcat, it provides the memory leak (WebappClassloader was leaked).
The situation is very strange.
When I add only API GET endpoint, then no leaks. WebappClassloader correctly unload.
When I add before or after spark filter, then WebappClassloader leaked.
I have prepared the simple code for demonstration https://bitbucket.org/lavelas/nashorn-memory-leak.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Pull source from https://bitbucket.org/lavelas/nashorn-memory-leak
2. Create war file by command mvn package
3. Start Tomcat
4. Deploy war from step 2
5. Undeploy war from step 2
6. Repeat steps 5-4 few times
7. Check memory leak report (for example in default Tomcat manager)
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
No memory leaks
ACTUAL -
The WebappClassloader was leaked
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import spark.servlet.SparkApplication;
import javax.script.*;
/**
* Spark filter with demonstration memory leak in Nashorn
*/
public class NashornSpark implements SparkApplication {
public void init() {
ScriptEngineManager sem = new ScriptEngineManager();
ScriptEngine nashorn = sem.getEngineByName("nashorn");
try {
nashorn.eval(
"var spark = {};\n" +
"spark.before = Packages.spark.Spark.before;\n" +
"spark.get = Packages.spark.Spark.get;\n" +
"spark.before('/*', function (request, response) { print('before') });\n" + // <------ Comment this line FIX memory leak!!!
"spark.get('/*', function (request, response) { return 'Hello spark!' });" +
""
);
} catch (ScriptException e) {
e.printStackTrace();
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Restart Tomcat