应用在运行过程中突然崩溃或功能异常(如网络请求一直失败、文件无法写入)。
查看HiLog日志,搜索PROCESS_KILL.*包名出现Reason为ResourceLeak:Fd Leak错误信息。
另外,在ArkTS层创建PixelMap对象给Image组件使用时,当Image组件销毁时,若未及时释放PixelMap所占用的fd,也会导致fd资源泄漏。
import { fs } from '@kit.CoreFileKit';
import { common } from '@kit.AbilityKit';
@Entry
@Component
struct Index {
@State leakCount: number = 0;
// 模拟泄漏:只打开不关闭
triggerLeak() {
let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
let path = context.filesDir + '/test_leak.txt';
// 创建一个文件用于测试
try {
let file = fs.openSync(path, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
fs.closeSync(file);
} catch (e) {
console.error('File operation failed:' + JSON.stringify(e));
}
// 循环打开文件,模拟泄漏
for (let i = 0; i < 500; i++) {
try {
// 错误:这里打开了文件句柄,但是没有保存引用,也没有调用close
let file = fs.openSync(path, fs.OpenMode.READ_WRITE);
this.leakCount++;
console.info(`Open fd success: ${file.fd}`);
} catch (e) {
console.error(`Open failed: ${JSON.stringify(e)}`);
}
}
}
build() {
Column() {
Text('当前模拟泄漏次数: ' + this.leakCount)
.fontSize(20)
.margin(20)
Button('点击触发fd泄漏')
.fontSize(20)
.onClick(() => {
this.triggerLeak();
})
}
.width('100%')
.height('100%')
}
} 日志路径通常位于/data/log/reliability/resource_leak/或通过导出故障日志获取。打开日志文件(如1380_fd_leak.txt),按以下顺序分析:
time: 2024/06/27 11:55:28 pid: 1380 process: com.example.myapp leaked fd nums: 5111 <-- 当前持有的句柄总数,远超正常值
Leaked fd Top 10: 4796 Ashmem <-- 绝大多数泄漏是共享内存 259 socket // ...
如下所示,可以明确看到是RDB数据库文件发生了泄漏:
Dir Type Top 10: 6175 /data/storage/el2/database/rdb <-- 明确指向数据库文件 5 /dev/urandom
在日志下方的LOGGER_MEMCHECK_FD_STACK_INFO区域,系统记录了句柄申请的调用栈(需开启开发者模式或Log版本)。
-num:表示该堆栈产生的句柄数量(未释放的)。
-bt:调用栈的程序计数器(PC)地址。
==============================Sorted by num============================== num 8272 bt [/system/lib64/libfdleak_tracker.so+0x1fb58] ... [/data/storage/el1/bundle/libs/arm64/libentry.so+0x148940]
使用SDK提供的addr2line工具,将bt中的地址还原为代码行号。
假设泄漏发生在libentry.so的0x148940处:
# 命令行示例 addr2line -C -f -e /path/to/libentry.so 0x148940
输出结果将直接指向代码中执行open、socket或napi_create_dataview(对应Ashmem)的具体行数。