Skip to content

Commit 06170d5

Browse files
Close ExternalSummary class loaders right after use (#5515)
It seems the class loaders used by ExternalSummary are only used right after having been created, and aren't needed anymore after that. So the changes here make sure we do close them right after.
1 parent 8478435 commit 06170d5

File tree

2 files changed

+41
-38
lines changed

2 files changed

+41
-38
lines changed

integration/feature/leak-hygiene/src/LeakHygieneTests.scala

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@ import utest._
1414
*/
1515
object LeakHygieneTests extends UtestIntegrationTestSuite {
1616
def checkClassloaders(tester: IntegrationTester)(kvs: (String, Int)*) = {
17-
val res = tester.eval(("show", "countClassLoaders"))
17+
val res = tester.eval(("show", "countClassLoaders"), check = true)
1818

1919
val read = upickle.default.read[SortedMap[String, Int]](res.out)
2020
val expected = SortedMap(kvs*)
21-
// pprint.log(read)
22-
// pprint.log(expected)
21+
if (read != expected) {
22+
pprint.log(expected)
23+
pprint.log(read)
24+
}
2325
assert(read == expected)
2426
}
2527

@@ -64,7 +66,6 @@ object LeakHygieneTests extends UtestIntegrationTestSuite {
6466
mill.constants.DebugLog("\nstart")
6567
checkClassloaders(tester)(
6668
"mill.daemon.MillBuildBootstrap#processRunClasspath classLoader cl" -> 1,
67-
"mill.codesig.ExternalSummary.apply upstreamClassloader" -> 1,
6869
"mill.javalib.JvmWorkerModule#worker cl" -> 1,
6970
"mill.javalib.worker.JvmWorkerImpl#scalaCompilerCache.setup loader" -> 1
7071
)
@@ -85,7 +86,6 @@ object LeakHygieneTests extends UtestIntegrationTestSuite {
8586
tester.eval(("show", "clean"))
8687
tester.eval(("show", "__.compile"))
8788
checkClassloaders(tester)(
88-
"mill.codesig.ExternalSummary.apply upstreamClassloader" -> 1,
8989
"mill.daemon.MillBuildBootstrap#processRunClasspath classLoader cl" -> 1,
9090
"mill.kotlinlib.KotlinWorkerManager" -> 1,
9191
"mill.javalib.JvmWorkerModule#worker cl" -> 2,
@@ -110,7 +110,6 @@ object LeakHygieneTests extends UtestIntegrationTestSuite {
110110
for (i <- Range(0, 2)) {
111111
tester.eval(("show", "__.compile"))
112112
checkClassloaders(tester)(
113-
"mill.codesig.ExternalSummary.apply upstreamClassloader" -> 1,
114113
"mill.daemon.MillBuildBootstrap#processRunClasspath classLoader cl" -> 1,
115114
"mill.kotlinlib.KotlinWorkerManager" -> 1,
116115
"mill.javalib.JvmWorkerModule#worker cl" -> 2,
@@ -133,7 +132,7 @@ object LeakHygieneTests extends UtestIntegrationTestSuite {
133132

134133
// Exercise post-shutdown
135134

136-
tester.eval(("shutdown"))
135+
tester.eval(("shutdown"), check = true)
137136
checkClassloaders(tester)(
138137
"mill.daemon.MillBuildBootstrap#processRunClasspath classLoader cl" -> 1,
139138
"mill.javalib.JvmWorkerModule#worker cl" -> 1

runner/codesig/src/mill/codesig/ExternalSummary.scala

Lines changed: 35 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import org.objectweb.asm.{ClassReader, ClassVisitor, MethodVisitor, Opcodes}
66

77
import java.net.URLClassLoader
88

9+
import scala.util.Using
10+
911
case class ExternalSummary(
1012
directMethods: Map[JCls, Map[MethodSig, Boolean]],
1113
directAncestors: Map[JCls, Set[JCls]],
@@ -27,47 +29,49 @@ object ExternalSummary {
2729
localSummary: LocalSummary,
2830
upstreamClasspath: Seq[os.Path]
2931
)(implicit st: SymbolTable): ExternalSummary = {
30-
val upstreamClassloader = mill.util.Jvm.createClassLoader(
32+
def createUpstreamClassloader() = mill.util.Jvm.createClassLoader(
3133
upstreamClasspath,
3234
getClass.getClassLoader
3335
)
3436

35-
val allDirectAncestors = localSummary.mapValuesOnly(_.directAncestors).flatten
36-
37-
val allMethodCallParamClasses = localSummary
38-
.mapValuesOnly(_.methods.values)
39-
.flatten
40-
.flatMap(_.calls)
41-
.flatMap(call => Seq(call.cls) ++ call.desc.args)
42-
.collect { case c: JType.Cls => c }
43-
4437
val methodsPerCls = collection.mutable.Map.empty[JCls, Map[MethodSig, Boolean]]
4538
val ancestorsPerCls = collection.mutable.Map.empty[JCls, Set[JCls]]
4639
val directSuperclasses = collection.mutable.Map.empty[JCls, JCls]
4740

48-
def load(cls: JCls): Unit = methodsPerCls.getOrElse(cls, load0(cls))
49-
50-
def load0(cls: JCls): Unit = {
51-
val visitor = new MyClassVisitor()
52-
val resourcePath =
53-
os.resource(upstreamClassloader) / os.SubPath(cls.name.replace('.', '/') + ".class")
54-
55-
new ClassReader(os.read.inputStream(resourcePath)).accept(
56-
visitor,
57-
ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG
58-
)
59-
60-
directSuperclasses(cls) = visitor.superclass
61-
methodsPerCls(cls) = visitor.methods
62-
ancestorsPerCls(cls) = visitor.ancestors
63-
ancestorsPerCls(cls).foreach(load)
41+
Using.resource(createUpstreamClassloader()) { upstreamClassloader =>
42+
val allDirectAncestors = localSummary.mapValuesOnly(_.directAncestors).flatten
43+
44+
val allMethodCallParamClasses = localSummary
45+
.mapValuesOnly(_.methods.values)
46+
.flatten
47+
.flatMap(_.calls)
48+
.flatMap(call => Seq(call.cls) ++ call.desc.args)
49+
.collect { case c: JType.Cls => c }
50+
51+
def load(cls: JCls): Unit = methodsPerCls.getOrElse(cls, load0(cls))
52+
53+
def load0(cls: JCls): Unit = {
54+
val visitor = new MyClassVisitor()
55+
val resourcePath =
56+
os.resource(upstreamClassloader) / os.SubPath(cls.name.replace('.', '/') + ".class")
57+
58+
new ClassReader(os.read.inputStream(resourcePath)).accept(
59+
visitor,
60+
ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG
61+
)
62+
63+
directSuperclasses(cls) = visitor.superclass
64+
methodsPerCls(cls) = visitor.methods
65+
ancestorsPerCls(cls) = visitor.ancestors
66+
ancestorsPerCls(cls).foreach(load)
67+
}
68+
69+
(allDirectAncestors ++ allMethodCallParamClasses)
70+
.filter(!localSummary.contains(_))
71+
.toSet
72+
.foreach(load)
6473
}
6574

66-
(allDirectAncestors ++ allMethodCallParamClasses)
67-
.filter(!localSummary.contains(_))
68-
.toSet
69-
.foreach(load)
70-
7175
ExternalSummary(methodsPerCls.toMap, ancestorsPerCls.toMap, directSuperclasses.toMap)
7276
}
7377

0 commit comments

Comments
 (0)