import java.io.IOException; import java.lang.management.ManagementFactory; import java.util.concurrent.Semaphore; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; import com.sun.management.HotSpotDiagnosticMXBean; public class ThreadMemoryLeak { private static final Semaphore sync = new Semaphore(1); public static void thread(final ScriptEngine scriptEngine, final long n) { new Thread(() -> { try { final long m = ((Long) scriptEngine.eval(n + " - 1")).longValue(); if (m > 0) thread(scriptEngine, m); else sync.release(); } catch (final ScriptException e) { e.printStackTrace(); } }).start(); } public static void main(final String[] args) throws IOException, InterruptedException { System.setProperty("org.jruby.embed.compat.version", "JRuby2.3"); System.setProperty("org.jruby.embed.localcontext.scope", "concurrent"); System.setProperty("org.jruby.embed.localvariable.behavior", "transient"); final ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("jruby"); sync.acquire(); thread(scriptEngine, 10000); sync.acquire(); // wait for threads to count down System.gc(); Thread.sleep(1000); dumpHeap("jruby-memory-leak.hprof"); } public static void dumpHeap(final String path) throws IOException { ManagementFactory .newPlatformMXBeanProxy(ManagementFactory.getPlatformMBeanServer(), "com.sun.management:type=HotSpotDiagnostic", HotSpotDiagnosticMXBean.class) .dumpHeap(path, true); } }