Memory leaked every time `formatKotlin` task is run
See original GitHub issueIt seems like each invocation of formatKotlin
leaks tens of MiB of heap on a small codebase (2500loc). This is using Gradle 7.0 with kotlinter 3.4.4 and kotlin 1.5.0.
Here’s the sequence of output from the class histogram (obtained via jcmd 15861 GC.run && jcmd 15861 GC.class_histogram | grep kotlin | head
) after running the formatKotlin
task several times, capturing the histogram after each run:
% jcmd 15861 GC.run && jcmd 15861 GC.class_histogram | grep kotlin | head
15861:
Command executed successfully
3: 502184 16069888 org.jetbrains.kotlin.name.FqNameUnsafe
4: 502184 12052416 org.jetbrains.kotlin.name.FqName
5: 502183 12052392 org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo$Exports
9: 236643 5679432 org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo$Requires
10: 228052 5473248 org.jetbrains.kotlin.cli.jvm.modules.CoreJrtVirtualFile
13: 93720 2249280 org.jetbrains.kotlin.resolve.jvm.modules.JavaModule$Explicit
14: 93720 2249280 org.jetbrains.kotlin.resolve.jvm.modules.JavaModule$Root
15: 93720 2249280 org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo
22: 17219 964264 org.jetbrains.kotlin.com.intellij.openapi.extensions.impl.InterfaceExtensionPoint
23: 39831 955944 org.jetbrains.kotlin.cli.jvm.index.JavaRoot
% jcmd 15861 GC.run && jcmd 15861 GC.class_histogram | grep kotlin | head
15861:
Command executed successfully
3: 547837 17530784 org.jetbrains.kotlin.name.FqNameUnsafe
4: 547837 13148088 org.jetbrains.kotlin.name.FqName
5: 547836 13148064 org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo$Exports
9: 258156 6195744 org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo$Requires
10: 248784 5970816 org.jetbrains.kotlin.cli.jvm.modules.CoreJrtVirtualFile
13: 102240 2453760 org.jetbrains.kotlin.resolve.jvm.modules.JavaModule$Explicit
14: 102240 2453760 org.jetbrains.kotlin.resolve.jvm.modules.JavaModule$Root
15: 102240 2453760 org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo
22: 18781 1051736 org.jetbrains.kotlin.com.intellij.openapi.extensions.impl.InterfaceExtensionPoint
23: 43452 1042848 org.jetbrains.kotlin.cli.jvm.index.JavaRoot
% jcmd 15861 GC.run && jcmd 15861 GC.class_histogram | grep kotlin | head
15861:
Command executed successfully
3: 593490 18991680 org.jetbrains.kotlin.name.FqNameUnsafe
4: 593490 14243760 org.jetbrains.kotlin.name.FqName
5: 593489 14243736 org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo$Exports
9: 279669 6712056 org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo$Requires
10: 269516 6468384 org.jetbrains.kotlin.cli.jvm.modules.CoreJrtVirtualFile
13: 110760 2658240 org.jetbrains.kotlin.resolve.jvm.modules.JavaModule$Explicit
14: 110760 2658240 org.jetbrains.kotlin.resolve.jvm.modules.JavaModule$Root
15: 110760 2658240 org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo
22: 20343 1139208 org.jetbrains.kotlin.com.intellij.openapi.extensions.impl.InterfaceExtensionPoint
23: 47073 1129752 org.jetbrains.kotlin.cli.jvm.index.JavaRoot
% jcmd 15861 GC.run && jcmd 15861 GC.class_histogram | grep kotlin | head
15861:
Command executed successfully
3: 639143 20452576 org.jetbrains.kotlin.name.FqNameUnsafe
4: 639143 15339432 org.jetbrains.kotlin.name.FqName
5: 639142 15339408 org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo$Exports
9: 301182 7228368 org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo$Requires
10: 290248 6965952 org.jetbrains.kotlin.cli.jvm.modules.CoreJrtVirtualFile
13: 119280 2862720 org.jetbrains.kotlin.resolve.jvm.modules.JavaModule$Explicit
14: 119280 2862720 org.jetbrains.kotlin.resolve.jvm.modules.JavaModule$Root
15: 119280 2862720 org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo
21: 21905 1226680 org.jetbrains.kotlin.com.intellij.openapi.extensions.impl.InterfaceExtensionPoint
22: 50694 1216656 org.jetbrains.kotlin.cli.jvm.index.JavaRoot
Here’s the same type of data, this time on a fresh daemon (./gradlew --stop && ./gradlew classes
to create a warmed up daemon), then showing the first two invocations of formatKotlin
.
% jcmd 16318 GC.run && jcmd 16318 GC.class_histogram | grep kotlin | head
16318:
Command executed successfully
17: 5254 210160 kotlin.reflect.jvm.internal.impl.protobuf.SmallSortedMap$1
21: 1817 159896 kotlin.reflect.jvm.internal.impl.metadata.ProtoBuf$Type
26: 5254 126096 kotlin.reflect.jvm.internal.impl.protobuf.FieldSet
33: 1072 94336 kotlin.reflect.jvm.internal.impl.metadata.ProtoBuf$Function
42: 1203 76992 kotlin.reflect.jvm.internal.impl.metadata.ProtoBuf$ValueParameter
47: 2570 61680 kotlin.reflect.jvm.internal.impl.name.Name
49: 2478 59472 kotlin.reflect.jvm.internal.ReflectProperties$LazySoftVal
58: 515 45320 kotlin.reflect.jvm.internal.impl.metadata.ProtoBuf$Property
62: 1226 39232 kotlin.reflect.jvm.internal.impl.name.FqNameUnsafe
70: 847 33880 kotlin.reflect.jvm.internal.impl.metadata.jvm.JvmProtoBuf$JvmMethodSignature
% jcmd 16318 GC.run && jcmd 16318 GC.class_histogram | grep kotlin | head
16318:
Command executed successfully
8: 45654 1460928 org.jetbrains.kotlin.name.FqNameUnsafe
10: 45654 1095696 org.jetbrains.kotlin.name.FqName
11: 45653 1095672 org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo$Exports
19: 21513 516312 org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo$Requires
20: 20732 497568 org.jetbrains.kotlin.cli.jvm.modules.CoreJrtVirtualFile
26: 5535 221400 kotlin.reflect.jvm.internal.impl.protobuf.SmallSortedMap$1
27: 8520 204480 org.jetbrains.kotlin.resolve.jvm.modules.JavaModule$Explicit
28: 8520 204480 org.jetbrains.kotlin.resolve.jvm.modules.JavaModule$Root
29: 8520 204480 org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo
32: 1976 173888 kotlin.reflect.jvm.internal.impl.metadata.ProtoBuf$Type
% jcmd 16318 GC.run && jcmd 16318 GC.class_histogram | grep kotlin | head
16318:
Command executed successfully
4: 91307 2921824 org.jetbrains.kotlin.name.FqNameUnsafe
6: 91307 2191368 org.jetbrains.kotlin.name.FqName
7: 91306 2191344 org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo$Exports
14: 43026 1032624 org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo$Requires
15: 41464 995136 org.jetbrains.kotlin.cli.jvm.modules.CoreJrtVirtualFile
24: 17040 408960 org.jetbrains.kotlin.resolve.jvm.modules.JavaModule$Explicit
25: 17040 408960 org.jetbrains.kotlin.resolve.jvm.modules.JavaModule$Root
26: 17040 408960 org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleInfo
30: 5535 221400 kotlin.reflect.jvm.internal.impl.protobuf.SmallSortedMap$1
32: 3161 177016 org.jetbrains.kotlin.com.intellij.openapi.extensions.impl.InterfaceExtensionPoint
I’ve attached a heap graph created with my heap analysis tools in case that’s instructive. It’s clear that there are a whole lot of PicoContainers being made, among other kotlin internal classes, so perhaps there is some reference being cached when it shouldn’t be either in the plugin or in ktlint itself?
Issue Analytics
- State:
- Created 2 years ago
- Comments:11 (7 by maintainers)
Top GitHub Comments
I haven’t forgotten about this issue, but I haven’t had the chance to delve into the guts of ktlint where the leak most likely is. hiding. I have a feeling, not scientific whatsoever, that ktlint is going to spin a new release soon upgrading to kotlin 1.5 and this leak will be fixed. I could be wrong though.
I made a teeny tiny repro project: https://github.com/marshallpierce/kotlinter-leak-repro
With less code it leaks more slowly but it’s still leaking (easily visible with GC.class_histogram).