summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Zaugg <jzaugg@gmail.com>2013-11-08 14:38:48 +0100
committerJason Zaugg <jzaugg@gmail.com>2014-01-10 10:44:25 +0100
commit00e11ffdd45a7be544b1566bf21cd4396381750e (patch)
treeeb1a585b4bd7e301def4d8216e073972c76c24b7
parent4e4c15177b92ef25f098277dcce3f874c24640b2 (diff)
downloadscala-00e11ffdd45a7be544b1566bf21cd4396381750e.tar.gz
scala-00e11ffdd45a7be544b1566bf21cd4396381750e.tar.bz2
scala-00e11ffdd45a7be544b1566bf21cd4396381750e.zip
SI-8129 Plug a leak in perRunCaches
I guess we've never leaned to heavily on these, because the registry of caches was forgetting about most of them immediately if they compared == at the point of creation. Consequently, maps like `treatedInfos` in Mixin were holding onto old types and symbols and leaking memory. You can reproduce the leak with: (for i in {1..200}; do echo src/library/scala/collection/*.scala; done; printf "\n") | scalac-hash v2.11.0-M7 -J-Xmx256M -Xresident nsc> warning: there were 6 deprecation warning(s); re-run with -deprecation for details (... 15 times) nsc> java.lang.OutOfMemoryError: GC overhead limit exceeded Dumping heap to java_pid90362.hprof ... Heap dump file created [340635728 bytes in 7.993 secs] ^CException in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded As a consequence of this change, I had to remove eager clearing of the uniques types cache. The comment in the code elaborates further.
-rw-r--r--src/reflect/scala/reflect/internal/SymbolTable.scala12
-rw-r--r--src/reflect/scala/reflect/internal/Types.scala7
2 files changed, 12 insertions, 7 deletions
diff --git a/src/reflect/scala/reflect/internal/SymbolTable.scala b/src/reflect/scala/reflect/internal/SymbolTable.scala
index 0ce5a0fbea..e6701b818a 100644
--- a/src/reflect/scala/reflect/internal/SymbolTable.scala
+++ b/src/reflect/scala/reflect/internal/SymbolTable.scala
@@ -344,16 +344,18 @@ abstract class SymbolTable extends macros.Universe
// Weak references so the garbage collector will take care of
// letting us know when a cache is really out of commission.
- private val caches = WeakHashSet[Clearable]()
+ import java.lang.ref.WeakReference
+ private var caches = List[WeakReference[Clearable]]()
def recordCache[T <: Clearable](cache: T): T = {
- caches += cache
+ caches ::= new WeakReference(cache)
cache
}
def clearAll() = {
debuglog("Clearing " + caches.size + " caches.")
- caches foreach (_.clear)
+ caches foreach (ref => Option(ref.get).foreach(_.clear))
+ caches = caches.filterNot(_.get == null)
}
def newWeakMap[K, V]() = recordCache(mutable.WeakHashMap[K, V]())
@@ -364,9 +366,9 @@ abstract class SymbolTable extends macros.Universe
val NoCached: T = null.asInstanceOf[T]
var cached: T = NoCached
var cachedRunId = NoRunId
- caches += new Clearable {
+ recordCache(new Clearable {
def clear(): Unit = cached = NoCached
- }
+ })
() => {
if (currentRunId != cachedRunId || cached == NoCached) {
cached = f
diff --git a/src/reflect/scala/reflect/internal/Types.scala b/src/reflect/scala/reflect/internal/Types.scala
index 99e6ae633f..d8bbd981b9 100644
--- a/src/reflect/scala/reflect/internal/Types.scala
+++ b/src/reflect/scala/reflect/internal/Types.scala
@@ -8,7 +8,6 @@ package reflect
package internal
import scala.collection.{ mutable, immutable, generic }
-import generic.Clearable
import scala.ref.WeakReference
import mutable.ListBuffer
import Flags._
@@ -3660,7 +3659,11 @@ trait Types
if (Statistics.canEnable) Statistics.incCounter(rawTypeCount)
if (uniqueRunId != currentRunId) {
uniques = util.WeakHashSet[Type](initialUniquesCapacity)
- perRunCaches.recordCache(uniques)
+ // JZ: We used to register this as a perRunCache so it would be cleared eagerly at
+ // the end of the compilation run. But, that facility didn't actually clear this map (SI-8129)!
+ // When i fixed that bug, run/tpeCache-tyconCache.scala started failing. Why was that?
+ // I've removed the registration for now. I don't think its particularly harmful anymore
+ // as a) this is now a weak set, and b) it is discarded completely before the next run.
uniqueRunId = currentRunId
}
(uniques findEntryOrUpdate tp).asInstanceOf[T]