Android 编译 gradle 内存 OOM 解决之路(一)

简介: Android 编译 gradle 内存 OOM 解决之路

背景


最近项目在编译,编译多次之后,有挺多人反馈会出现 OOM 的,在项目的根目录下面会出现 hs_err_pid*.log 的错误文件。内容大概如下


ba613cd0cd5dd862aa9119325a3fffda_986d75087c70e2451098d7db560f5ab7.png


这个对我们的开发效率还是有挺大影响的,如果能够解决,对我们的开发效率还是有一定提升的。因此,我们尝试进行解决。


探索原因


从报错的信息来看,‘jar transform Thread’ 有时候的线程数非常多, 很有可能是同时开启的线程数过大,导致内存不足,最终 OOM。


从线程名是 ‘jar transform Thread’ ,根据经验,我们第一时间想到可能是 transform 相关的。


于是,我们找项目当中 transfrom 相关的, 从 buildScan 文件中,找 transfrom 相关的


fb2d08fd2cba75921afca90431a352e3_eb849ef08a0e458fad40bcf2b72ae5e7.png


发现主要有几个


  1. transformClassesWithRealmTransformerForDebug
  2. transformClassesWithCom.xx.xx.gradle.plugin.hilt.HiltContextWrapperRemovePluginForDebug
  3. transformDebugClassesWithAsm


很快我们找到 Hilt, Realm 里面 transform 里面的代码,发现里面的 Thread Name 都不是 jar transform Thread。那应该不是这两个的原因。


讨论之后,我们尝试 dump 编译时 Java 进程的内存信息,看能不能复现?


首先,我们先确定当前进程的 PID


3f54813fc697d6ccd7441b7088d02b80_866ad1c1111cb18d4cea18c4ca5fcbd2.png


接着我们借助 VisualVM 这个工具,dump 下 JVM 编译时候的进程,编译的时候发现,线程数有时候会越来越多。


8d5b928b41bcee5a74363bd3db617588_d9a5944a2d908522030cadd89d3126f3.png


于是,我们在想能不能 debug 创建线程的地方,于是,我们在 java.lang.Thread#setName 这里设置条件断点 name.contains("jar transform")


68430a733572f185653a402deeb9994a_59ccdb48be5daa03c640c2a9c2ddf636.png


debug gradle assembleDebug 任务,很快我们发现,调用栈关系如下


3c3091509e9f7dc3865e1d93114a8779_801af5630465093e10c0136ac0e0f7a9.png


我们重点关注到了几个跟线程相关的东西


198569d65064abc0735a474e26f3434a_dd634c46d7f1b94a1e364af2315c0573.png


我们跟踪进去,发现这个线程池的核心线程数设置为 2147483647


7c57a1829769f9a4fb689da6d33ca847_9ba168670059b22d7fd17b80844d4d33.png


而上面的线程数不断增多,并且线程名包括 “jar transform”, 那很有可能就是这个线程池了。


我们逐一排查,发现线程池 executor 是在这里传递进来的


49d4b957923d21bfc4234162925c704a_eab8bd761453da20b73167e6da720bd3.png


跟踪代码,很快我们发现创建改线程池 executor 的地方DefaultCachedClasspathTransformer#executor


bc9a1cdf42835b481d87105aab92365a_9ab0f1a3db06ac0bc742412bfe6d7e8e.png


他这里果然没有限制线程的数量。


而我们项目中的 gradle 代码是 6.9.1,于是在想,我们去跟官方最新代码对比一下。


相关文章
|
1月前
|
Android开发
Android基于gradle task检查各个module之间资源文件冲突情况
Android基于gradle task检查各个module之间资源文件冲突情况
Android基于gradle task检查各个module之间资源文件冲突情况
|
1月前
|
存储 前端开发 Java
Android MVVM架构模式下如何避免内存泄漏
Android采用MVVM架构开发项目,如何避免内存泄漏风险?怎样避免内存泄漏?
88 1
|
8天前
|
Android开发 开发者
Android性能优化——内存管理的艺术
Android性能优化——内存管理的艺术
|
1月前
|
Android开发
Android gradle task任务检查各个module之间资源文件冲突.md
Android gradle task任务检查各个module之间资源文件冲突.md
Android gradle task任务检查各个module之间资源文件冲突.md
|
1月前
|
存储 程序员 编译器
简述 C、C++程序编译的内存分配情况
在C和C++程序编译过程中,内存被划分为几个区域进行分配:代码区存储常量和执行指令;全局/静态变量区存放全局变量及静态变量;栈区管理函数参数、局部变量等;堆区则用于动态分配内存,由程序员控制释放,共同支撑着程序运行时的数据存储与处理需求。
101 21
|
29天前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
81 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
1月前
|
编解码 Android开发 UED
构建高效Android应用:从内存优化到用户体验
【10月更文挑战第11天】本文探讨了如何通过内存优化和用户体验改进来构建高效的Android应用。介绍了使用弱引用来减少内存占用、懒加载资源以降低启动时内存消耗、利用Kotlin协程进行异步处理以保持UI流畅,以及采用响应式设计适配不同屏幕尺寸等具体技术手段。
49 2
|
1月前
|
编译器 Android开发
配置环境变量,使CMakeLists.txt可直接使用Android NDK工具链编译项目
配置环境变量,使CMakeLists.txt可直接使用Android NDK工具链编译项目
|
1月前
|
Ubuntu Shell API
Ubuntu 64系统编译android arm64-v8a 的openssl静态库libssl.a和libcrypto.a
Ubuntu 64系统编译android arm64-v8a 的openssl静态库libssl.a和libcrypto.a
|
1月前
|
Java Android开发 Windows
玩转安卓之配置gradle-8.2.1
为安卓开发配置Gradle 8.2.1,包括下载和解压Gradle、配置环境变量、修改配置文件以增加国内镜像,以及在Android Studio中配置Gradle和JDK的过程。
73 0
玩转安卓之配置gradle-8.2.1