What is the cause of this strange Scala memory lea

2019-05-22 16:49发布

问题:

This question already has an answer here:

  • is memory leak? why java.lang.ref.Finalizer eat so much memory 2 answers

Even with 7G of heap space, this will run out of memory.

import scala.collection.mutable.Set

class Foo() {
  val anEmptySet: Set[Int] = Set()
  def bar(ints: Traversable[Int]): Unit = {}
  override def finalize() {
    bar(anEmptySet)
    super.finalize()
  }

}

object FooTest {
  def main(args: Array[String]): Unit = {
    for (i <- 0 to 100000000) {
      val f = new Foo()
    }
  }
}

What is causing the problem, and how can it be avoided? The problem seems to be the call to bar in the finalize method, but I don't understand why it would leak memory. I know that typical classes don't need to override finalize, but it is necessary in the real version of this code.

回答1:

As I said in the comments, this is not at all a Scala-specific problem. finalize comes straight from java.lang.Object. The problem is described very well by this answer, though I would hesitate to say that this question is an exact duplicate.

The gist of it is that finalize needs to be called by something. But when you're creating 100 billion objects in rapid succession, they are getting created much faster than they can be finalized. The thread needs to be available to call finalize, but it isn't because it's too busy creating more objects.

How can you fix it? You could start by not creating 100 billion instances of the same object in rapid succession. I know this is just a toy example, but in the real world you'll have to try to avoid allocating too many of these at the same time. And given this is not the actual code in question, it's harder to give better advice.