背景
最近项目在编译,编译多次之后,有挺多人反馈会出现 OOM 的,在项目的根目录下面会出现 hs_err_pid*.log 的错误文件。内容大概如下
这个对我们的开发效率还是有挺大影响的,如果能够解决,对我们的开发效率还是有一定提升的。因此,我们尝试进行解决。
探索原因
从报错的信息来看,‘jar transform Thread’ 有时候的线程数非常多, 很有可能是同时开启的线程数过大,导致内存不足,最终 OOM。
从线程名是 ‘jar transform Thread’ ,根据经验,我们第一时间想到可能是 transform 相关的。
于是,我们找项目当中 transfrom 相关的, 从 buildScan 文件中,找 transfrom 相关的
发现主要有几个
- transformClassesWithRealmTransformerForDebug
- transformClassesWithCom.xx.xx.gradle.plugin.hilt.HiltContextWrapperRemovePluginForDebug
- transformDebugClassesWithAsm
很快我们找到 Hilt, Realm 里面 transform 里面的代码,发现里面的 Thread Name 都不是 jar transform Thread。那应该不是这两个的原因。
讨论之后,我们尝试 dump 编译时 Java 进程的内存信息,看能不能复现?
首先,我们先确定当前进程的 PID
接着我们借助 VisualVM 这个工具,dump 下 JVM 编译时候的进程,编译的时候发现,线程数有时候会越来越多。
于是,我们在想能不能 debug 创建线程的地方,于是,我们在 java.lang.Thread#setName 这里设置条件断点 name.contains("jar transform")
debug gradle assembleDebug 任务,很快我们发现,调用栈关系如下
我们重点关注到了几个跟线程相关的东西
我们跟踪进去,发现这个线程池的核心线程数设置为 2147483647
而上面的线程数不断增多,并且线程名包括 “jar transform”, 那很有可能就是这个线程池了。
我们逐一排查,发现线程池 executor 是在这里传递进来的
跟踪代码,很快我们发现创建改线程池 executor 的地方DefaultCachedClasspathTransformer#executor
他这里果然没有限制线程的数量。
而我们项目中的 gradle 代码是 6.9.1,于是在想,我们去跟官方最新代码对比一下。