Skip to content

Commit 0d3ce98

Browse files
authored
Merge pull request scala/scala#9276 from jtjeferreira/class-tag-leak
fix ClassTag#cache leak
2 parents e72e6d3 + 4a24f5c commit 0d3ce98

File tree

1 file changed

+21
-5
lines changed

1 file changed

+21
-5
lines changed

library/src/scala/reflect/ClassTag.scala

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ package scala
1414
package reflect
1515

1616
import java.lang.{ Class => jClass }
17+
import java.lang.ref.{WeakReference => jWeakReference}
1718

1819
import scala.collection.mutable
1920
import scala.runtime.BoxedUnit
@@ -136,16 +137,19 @@ object ClassTag {
136137
val Nothing : ClassTag[scala.Nothing] = Manifest.Nothing
137138
val Null : ClassTag[scala.Null] = Manifest.Null
138139

139-
private[this] val cache = new ClassValue[ClassTag[_]] {
140-
override def computeValue(runtimeClass: jClass[_]): ClassTag[_] = {
140+
private val cacheDisabledProp = scala.sys.Prop[String]("scala.reflect.classtag.cache.disable")
141+
private[this] object cache extends ClassValue[jWeakReference[ClassTag[_]]] {
142+
override def computeValue(runtimeClass: jClass[_]): jWeakReference[ClassTag[_]] =
143+
new jWeakReference(computeTag(runtimeClass))
144+
145+
def computeTag(runtimeClass: jClass[_]): ClassTag[_] =
141146
runtimeClass match {
142147
case x if x.isPrimitive => primitiveClassTag(runtimeClass)
143148
case ObjectTYPE => ClassTag.Object
144149
case NothingTYPE => ClassTag.Nothing
145150
case NullTYPE => ClassTag.Null
146151
case _ => new GenericClassTag[AnyRef](runtimeClass)
147-
}
148-
}
152+
}
149153

150154
private def primitiveClassTag[T](runtimeClass: Class[_]): ClassTag[_] = runtimeClass match {
151155
case java.lang.Byte.TYPE => ClassTag.Byte
@@ -168,7 +172,19 @@ object ClassTag {
168172
}
169173
}
170174

171-
def apply[T](runtimeClass1: jClass[_]): ClassTag[T] = cache.get(runtimeClass1).asInstanceOf[ClassTag[T]]
175+
def apply[T](runtimeClass1: jClass[_]): ClassTag[T] = {
176+
if (cacheDisabledProp.isSet)
177+
cache.computeTag(runtimeClass1).asInstanceOf[ClassTag[T]]
178+
else {
179+
val ref = cache.get(runtimeClass1).asInstanceOf[jWeakReference[ClassTag[T]]]
180+
var tag = ref.get
181+
if (tag == null) {
182+
cache.remove(runtimeClass1)
183+
tag = cache.computeTag(runtimeClass1).asInstanceOf[ClassTag[T]]
184+
}
185+
tag
186+
}
187+
}
172188

173189
def unapply[T](ctag: ClassTag[T]): Option[Class[_]] = Some(ctag.runtimeClass)
174190
}

0 commit comments

Comments
 (0)