memory泄露分析方法(FD(File Descriptor)篇)

发布于:2025-02-11 ⋅ 阅读:(38) ⋅ 点赞:(0)

File Descriptor是Linux下概念,fd 是 int类型非负数!

进程打开File,Socket,Pipe后生成一个File Descriptor,它是打开这个系统资源的标识符。

Linux每个进程fd最大1024个,超过之后进程 crash,crash堆栈如下:

  •  使用匿名共享内存

E AndroidRuntime: java.lang.Error: java.io.IOException: SharedMemory_create failed: EMFILE (Too many open files)

F DEBUG : Abort message: 'FORTIFY: FD_SET: file descriptor 1462 >= FD_SETSIZE 1024'

  • 使用fd = open(filename, O_RDONLY) 打开文件

返回fd变量场景如下:

  1. epoll初始化:fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC) / fd = epoll_create1(EPOLL_CLOEXEC)
  2. 打开文件:fd = open(filename, O_RDONLY)
  3. 共享内存:fd = getParcelFileDescriptor(new MemoryFile(

还有更多隐蔽的生成了fd,如:new Socket,new Thread,new PipedOutputStream‘

如何监控fd泄漏?

  • StrictMode
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
    .detectDiskReads()
    .detectDiskWrites()
    .detectNetwork() // or .detectAll() for all detectable problems
    .penaltyLog()
    .build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
    .detectLeakedSqlLiteObjects()
    .detectLeakedClosableObjects()
    .penaltyLog()
    .penaltyDeath()
    .build());
  • 脚本定时读取fd:本地写shell/python脚本定时读取proc/pid/fd
  • shell命令读取fd总量或fd列表
 lsof -n -p pid  | wc -l 

fd标识符和泄漏文件类型关系

类型 fd标识符
网络请求 Socket
HandlerThread anon_inode:[eventpoll]和anon_inode:[eventfd]成对出现
in/output打开文件

/data/data/x,/data/app/x,/storage/emulate/0/x

例如 File(cacheDir, "file").createNewFile()

打开数据库文件 /dev/ashmem
InputChannel泄露时增加明显 anon_inode:[dmabuf]
线程

FD泄漏优化:

  • HandlerThread用完后要关闭(HandlerThread::quitSafely()/HandlerThread::quit())
  • 减少window数量:每增加1个window上涨10个fd
  • 停止无用的线程:1个线程增加1个fd

网站公告

今日签到

点亮在社区的每一天
去签到