3
votes

I have a program with a large immutable object that returns a modified version of itself when performing a certain operation. I try to test it in the sbt console, doing something like var myObj = getInitialObject(); and then repeatedly calling myObj = myObj.getNewOne();

There is no reference left to the old object, but the memory doesn't seem to get freed. Eventually I get an OutOfMemoryError: GC overhead limit exceeded. I was able to reproduce the problem with a simple example at a scala repl prompt:

scala> val foo = List.fill(1000000) { new Object() }
foo: List[java.lang.Object] = List(java.lang.Object@14fd510, java.lang.Object@202d0e1c, java.lang.Object@6df960c4, java.lang.Object@f401c44, java.lang.Object@39ffbc2e, java.lang.Object@449b8dc1, java.lang.Object@40779d17, java.lang.Object@6cea7211, java.lang.Object@13e6f1f4, java.lang.Object@1f16d461, java.lang.Object@13d13c39, java.lang.Object@dc8cc59, java.lang.Object@79dfee20, java.lang.Object@5c8ab562, java.lang.Object@168a6465, java.lang.Object@57c52e72, java.lang.Object@526c6b62, java.lang.Object@4bfe1934, java.lang.Object@1728cbe6, java.lang.Object@776274ea, java.lang.Object@60e9ebe1, java.lang.Object@1d7d327c, java.lang.Object@67d7a04, java.lang.Object@17d59ff0, java.lang.Object@49f751c9, java.lang.Object@c1a890f, java.lang.Object@221c3dfe, java.lang.Object@6c2a0030, java.lang.O...
scala> val foo = List.fill(1000000) { new Object() }
foo: List[java.lang.Object] = List(java.lang.Object@6e8fb561, java.lang.Object@1ccd2bfc, java.lang.Object@6202bc29,.... (ommiting the rest of the output)
scala> val foo = List.fill(1000000) { new Object() }
.... repeat a few more times and get:

scala> val foo = List.fill(1000000) { new Object() }
null

java.lang.OutOfMemoryError: GC overhead limit exceeded
    at scala.tools.nsc.transform.SpecializeTypes$$anonfun$13.apply(SpecializeTypes.scala:669)
    at scala.tools.nsc.transform.SpecializeTypes$$anonfun$13.apply(SpecializeTypes.scala:667)
    at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:200)
    at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:200)
    at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:59)
    at scala.collection.immutable.List.foreach(List.scala:45)
    at scala.collection.TraversableLike$class.flatMap(TraversableLike.scala:200)
    at scala.collection.immutable.List.flatMap(List.scala:45)
    at scala.tools.nsc.transform.SpecializeTypes.specializeClass(SpecializeTypes.scala:667)
    at scala.tools.nsc.transform.SpecializeTypes.transformInfo(SpecializeTypes.scala:1065)
    at scala.tools.nsc.transform.InfoTransform$Phase$$anon$1.transform(InfoTransform.scala:38)
.....
....

Using "var" without a re-declaration each time instead of val doesn't seem to help. How can I get the repl/sbt to free up / garbage collect the memory for that no-longer-relevant object reference?

1
Are you always running this from an interpreter? I would guess that the interpreter itself is holding a ref. The command line scala interpreter holds these so you can back-reference them. Try it in a real compiled program where you are sure you're letting go of it.Tony K.
yeah, I'm running this from the interpreter. The point is I want to be able to test my app from the interpreter though without running out of memory... it's just easier to test that way.nairbv

1 Answers