FD 泄露引发的AGP8 build 失败问题

项目升级到 AGP8 以后 一直有个问题,有一个 利用 jacoco 做代码覆盖率的插件 一直会导致项目编译失败,偶现,且 build 失败给出的 堆栈信息迷惑性很强,导致问题排查方向错了,最后发现是 FD 泄露导致的。

调整编译命令 给出更多报错信息以后 如下:

这里就很有迷惑性, 为什么报错在 r8 这里, 甚至堆栈里都明确给出了哪个类的哪个方法出现了问题

这让我的问题排查方向一直陷在 是字节码处理逻辑上的冲突导致, 然后就无用功了很久

最后是通过排除法 逐一把项目中所有字节码处理相关的场景1 个个去掉以后,定位到是某个 task 和 这个 jacoco 的不兼容导致

但是一时半会也没怀疑到跟文件描述符有关。

可以在 build task中 找到最后一个task,加个 doLast 的逻辑 while true 就可以 ,让 build 进程 一直 hang 在那里,方便我们查看进程情况

可以看出来这里 打开了 3600 多个文件实属不太正常

里面还有大量的 class 文件

最后修复了这个文件描述符泄露的问题以后,build 就成功了

理性猜测是agp8 以后,新增的 asm api 本质上是可以并行执行 aop task 的,这里面可能有更加严格的校验机制,导致 FD 泄露以后 校验机制出现异常 最后 build 失败,并且给出了错误的提示信息

脚本

用来统计 jvm 进程 所有文件描述符打开情况(指挥llm 写脚本是真的方便)

shell 复制代码
#!/bin/bash

# 检查 'jps' 命令是否存在
if ! command -v jps &> /dev/null; then
    echo "错误: 未找到 'jps' 命令。请确保 JDK 已安装并且其 bin 目录已添加到您的 PATH 环境变量中。"
    exit 1
fi

# 检查 'lsof' 命令是否存在
if ! command -v lsof &> /dev/null; then
    echo "错误: 未找到 'lsof' 命令。在 macOS 上,它通常是预装的。"
    exit 1
fi

# 显示当前系统时间
echo "扫描时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo "正在列出每个 JVM 进程打开的文件描述符详情..."
echo ""

# 使用 jps -l 获取 PID 和主类名
jps -l | while read -r pid name; do
    # 如果进程在 jps 和 lsof 命令之间退出了,lsof 会报错,所以先检查进程是否存在
    if ! ps -p "$pid" > /dev/null; then
        continue
    fi

    # 如果 name 为空 (例如 jps 进程本身),给一个默认值
    if [ -z "$name" ]; then
        name="<jps_process>"
    fi

    # 先用 lsof 统计文件描述符总数
    count=$(lsof -p "$pid" 2>/dev/null | wc -l)

    # 如果进程没有打开任何文件(或已退出),则跳过
    if [ "$count" -eq 0 ]; then
        continue
    fi

    echo "=========================================================================================="
    printf "PID: %-10s | Total FDs: %-8s | Main Class/JAR: %s\n" "$pid" "$count" "$name"
    echo "------------------------------------------------------------------------------------------"
    printf "%-15s %-8s %-12s %-10s %s\n" "COMMAND" "PID" "TYPE" "SIZE/OFF" "NAME"
    echo "------------------------------------------------------------------------------------------"

    # 使用 lsof 列出该进程打开的所有文件,并使用 awk 过滤掉不需要的列
    # 只保留 COMMAND, PID, TYPE, SIZE/OFF, NAME 这几列
    lsof -P -n -p "$pid" 2>/dev/null | awk 'NR>1 {printf "%-15s %-8s %-12s %-10s %s\n", $1, $2, $5, $7, $9}'

    echo "=========================================================================================="
    echo ""
done

echo "统计完成。"
相关推荐
一笑的小酒馆5 小时前
Android12去掉剪贴板复制成功的Toast
android
一笑的小酒馆5 小时前
Android12App启动图标自适应
android
程序员江同学6 小时前
Kotlin 技术月报 | 2025 年 7 月
android·kotlin
某空m8 小时前
【Android】内容提供器
android
Greenland_128 小时前
Android 编译报错 Null extracted folder for artifact: xxx activity:1.8.0
android
ZhuYuxi3339 小时前
【Kotlin】const 修饰的编译期常量
android·开发语言·kotlin
Bryce李小白9 小时前
Kotlin 实现 MVVM 架构设计总结
android·开发语言·kotlin
Kiri霧9 小时前
Kotlin位运算
android·开发语言·kotlin
xjdkxnhcoskxbco9 小时前
kotlin基础【3】
android·开发语言·kotlin
thginWalker10 小时前
MySQL图解索引篇
android·mysql·adb