Scala Programming Language
  1. Scala Programming Language
  2. SI-7130

Memory leak caused by scala.reflect.internal.util.Statistics

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Critical Critical
    • Resolution: Fixed
    • Affects Version/s: Scala 2.10.0, Scala 2.10.1-RC1
    • Fix Version/s: Scala 2.10.2-RC1
    • Component/s: None
    • Labels:
      None

      Description

      In Types.scala we have the following code:

        Statistics.newView("#unique types") { if (uniques == null) 0 else uniques.size }
      

      Let's have a closer look at Statistics.newView:

      def newView(prefix: String, phases: String*)(quant: => Any): View = new View(prefix, phases, quant)
      

      As you can see newView takes by-name argument (that in our case closes over the whole Global) and passes it to View.

      The View class inherits from Quantity that is defined as follows:

        trait Quantity {
          if (prefix.nonEmpty) {
            val key = s"${if (underlying != this) underlying.prefix else ""}/$prefix"
            qs(key) = this
          }
          val prefix: String
          val phases: Seq[String]
          def underlying: Quantity = this
          def showAt(phase: String) = phases.isEmpty || (phases contains phase)
          def line = f"$prefix%-30s: ${this}"
          val children = new mutable.ListBuffer[Quantity]
        }
      

      So we register this in global (defined in top-level object) HashMap stored in variable qs. The consequence is that even if you don't use Global it'll be still hanging there because Statistics holds reference to it. This is a memory leak that I observed while using Scala IDE where Global used for compiling the code was kept around and consumed aroung 0.5GB of heap.

        Activity

        Hide
        Grzegorz Kossakowski added a comment -

        Added Iulian to watchers as he might be interested in this ticket.

        Show
        Grzegorz Kossakowski added a comment - Added Iulian to watchers as he might be interested in this ticket.
        Hide
        Grzegorz Kossakowski added a comment -

        The simple solution to avoid memory leak is to turn all operations in Statistics into no-ops in case statistics is disabled.

        However, the whole design is broken because it doesn't work across many Globals. Also, life cycle of that top-level object is not clear to me since you can mutate enabled flag at any time.

        Show
        Grzegorz Kossakowski added a comment - The simple solution to avoid memory leak is to turn all operations in Statistics into no-ops in case statistics is disabled. However, the whole design is broken because it doesn't work across many Globals. Also, life cycle of that top-level object is not clear to me since you can mutate enabled flag at any time.
        Show
        James Iry added a comment - https://github.com/scala/scala/pull/2129

          People

          • Assignee:
            Grzegorz Kossakowski
            Reporter:
            Grzegorz Kossakowski
          • Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development