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 "统计完成。"
相关推荐
JMchen1239 小时前
Android UDP编程:实现高效实时通信的全面指南
android·经验分享·网络协议·udp·kotlin
黄林晴10 小时前
Android 17 再曝猛料:通知栏和快捷设置终于分家了,这操作等了十年
android
有位神秘人10 小时前
Android获取设备中本地音频
android·音视频
JMchen12310 小时前
Android网络安全实战:从HTTPS到双向认证
android·经验分享·网络协议·安全·web安全·https·kotlin
CS创新实验室11 小时前
Pandas 3 的新功能
android·ide·pandas
ujainu11 小时前
护眼又美观:Flutter + OpenHarmony 鸿蒙记事本一键切换夜间模式(四)
android·flutter·harmonyos
三少爷的鞋11 小时前
为什么我不在 Android ViewModel 中直接处理异常?
android
草莓熊Lotso12 小时前
Linux 文件描述符与重定向实战:从原理到 minishell 实现
android·linux·运维·服务器·数据库·c++·人工智能
恋猫de小郭12 小时前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
工程师老罗19 小时前
如何在Android工程中配置NDK版本
android