I need to implement a DSL (Domain Specific Language) using Scala, and this DSL will be interpreted in a Scala interpreter (scala.tools.nsc.interpreter). The problem is that the memory used by the interpreter keeps increasing until an outOfMemory exception is thrown. I cannot reinitialize the interpreter each time I have a line of DSL to execute, as the interpreter takes a while to load. I cannot just call reset(), as I need to keep track of some data in the execution environment of the interpreter.
Memory leak will happen even I do the following:
while (true)
{
interpreter.interpret("println(4 + 5)")
}
After a while, I'll get:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at ch.epfl.lamp.util.ByteArray.<init>(ByteArray.java:24)
at ch.epfl.lamp.fjbg.JCode.<init>(JCode.java:47)
at ch.epfl.lamp.fjbg.JExtendedCode.<init>(JExtendedCode.java:113)
at ch.epfl.lamp.fjbg.FJBGContext.JCode(FJBGContext.java:122)
at ch.epfl.lamp.fjbg.JMethod.<init>(JMethod.java:52)
at ch.epfl.lamp.fjbg.FJBGContext.JMethod(FJBGContext.java:87)
at ch.epfl.lamp.fjbg.JClass.addNewMethod(JClass.java:246)
at scala.tools.nsc.backend.jvm.GenJVM$BytecodeGenerator.genMethod(GenJVM.scala:755)
at scala.tools.nsc.backend.jvm.GenJVM$BytecodeGenerator$$anonfun$genClass$7.apply(GenJVM.scala:307)
at scala.tools.nsc.backend.jvm.GenJVM$BytecodeGenerator$$anonfun$genClass$7.apply(GenJVM.scala:307)
at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
at scala.collection.immutable.List.foreach(List.scala:45)
at scala.tools.nsc.backend.jvm.GenJVM$BytecodeGenerator.genClass(GenJVM.scala:307)
at scala.tools.nsc.backend.jvm.GenJVM$JvmPhase$$anonfun$run$4.apply(GenJVM.scala:86)
at scala.tools.nsc.backend.jvm.GenJVM$JvmPhase$$anonfun$run$4.apply(GenJVM.scala:86)
at scala.collection.mutable.HashMap$$anon$2$$anonfun$foreach$3.apply(HashMap.scala:102)
at scala.collection.mutable.HashMap$$anon$2$$anonfun$foreach$3.apply(HashMap.scala:102)
at scala.collection.Iterator$class.foreach(Iterator.scala:660)
at scala.collection.mutable.HashTable$$anon$1.foreach(HashTable.scala:157)
at scala.collection.mutable.HashTable$class.foreachEntry(HashTable.scala:190)
at scala.collection.mutable.HashMap.foreachEntry(HashMap.scala:43)
at scala.collection.mutable.HashMap$$anon$2.foreach(HashMap.scala:102)
at scala.tools.nsc.backend.jvm.GenJVM$JvmPhase.run(GenJVM.scala:86)
at scala.tools.nsc.Global$Run.compileSources(Global.scala:953)
at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.compileAndSaveRun(IMain.scala:756)
at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.compile(IMain.scala:731)
at scala.tools.nsc.interpreter.IMain$Request.compile(IMain.scala:873)
at scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:576)
at scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:543)
at com.ericsson.ims_dsl.IMS_Interpreter$$anonfun$e$1.apply(IMS_Interpreter.scala:50)
at com.ericsson.ims_dsl.IMS_Interpreter$$anonfun$e$1.apply(IMS_Interpreter.scala:50)
at scala.tools.nsc.interpreter.IMain.beQuietDuring(IMain.scala:200)
Could someone please help me solve this issue?
Every time you call the interpret
method, the request is stored. Therefore if you try to call an infinite number of time this method, you should run into trouble. So it's not really a bug.
You can increase the number of possible iterations before crash by increasing the JVM maximum heap size... You may want to count the number of possible calls to check if it meets your goal.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With