一个EMFILE问题定位:lsof、ulimit的应用,以及简单分析
2024-08-30 19:43:40
关键词:errno、EMFILE、ulimit、lsof等等。
背景是在对程序进行压力测试,运行了一段时间之后出现一个复位操作失败。
这个复位操作通过打开一个设备,进行读写操作,已达到控制GPIO输入输出的目的。
1. 初步分析原因
经过初步分析发觉fopen()返回NULL指针,说明fopen()错误了。
但是要想知道错误原因,还需要借助errno。通过errno为24,即可知道出错的原因为EMFILE。
由errno-base.h可知,EMFILE是打开文件过多的意思。
#define EMFILE 24 /* Too many open files */
2. 找到是谁打开了哪个文件而没有释放
首先明白系统对资源使用限制的,通过ulimit可以查看限制或者修改限制。
关于文件打开文件数目的限制通过ulimit -n查看,或者ulimit -n <file null>修改限制。
通过ulimit -n命令可以查看linux系统里打开文件描述符的最大值,一般缺省值是1024。
ulimit -a
-f: file size (blocks) unlimited
-t: cpu time (seconds) unlimited
-d: data seg size (kb) unlimited
-s: stack size (kb)
-c: core file size (blocks)
-m: resident set size (kb) unlimited
-l: locked memory (kb)
-p: processes
-n: file descriptors 1024
-v: address space (kb) unlimited
-w: locks unlimited
-e: scheduling priority
-r: real-time priority
lsof显示系统所有打开文件,那么很简单通过lsof即可查看到相关信息。
通过lsof可以看到打开的文件非常多,而且主要集中在uImage这个文件。
...
/heop/package/AiApp/AiApp /heop/package/AiApp/uImage
/heop/package/AiApp/AiApp /heop/package/AiApp/uImage
/heop/package/AiApp/AiApp /heop/package/AiApp/uImage
...
然后看到uImage这个文件被打开了1000多次,问题就很明了了。
通过走查代码,发现uImage文件在被打开后由于某些条件未fclose()。解决也比较简单。
3. EMFILE出现代码走查
open系统调用入口是do_sys_open(),通过get_unused_fd_flags()来获得可用的句柄号。
long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
{
...
fd = get_unused_fd_flags(flags);
if (fd >= ) {
...
}
putname(tmp);
return fd;
} SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode)
{
if (force_o_largefile())
flags |= O_LARGEFILE; return do_sys_open(AT_FDCWD, filename, flags, mode);
}
然后就看看句柄是如何分配的,以及有什么限制。
通过rlimit(RLIMIT_NOFILE)可以获得系统对打开文件数目的限制,等同于ulimit -n。
然后__alloc_fd()应该着这个范围之内。当判断fd>=end的时候,返回-EMFILE。
int get_unused_fd_flags(unsigned flags)
{
return __alloc_fd(current->files, , rlimit(RLIMIT_NOFILE), flags);
} int __alloc_fd(struct files_struct *files,
unsigned start, unsigned end, unsigned flags)
{
...
error = -EMFILE;
if (fd >= end)
goto out;
... out:
spin_unlock(&files->file_lock);
return error;
}
最新文章
- JavaScript Arguments.callee解释
- Android Studio 导入百度地图jar和so的正确方式
- 处理大并发之五 使用libevent利器bufferevent
- java socket 网络编程常见异常
- java操作数据库出错
- Warp divergence
- cocos2dx从入门到精通课程
- Android ContentProvider的实现
- 【笔记】UML核心元素
- CircleDisplay
- hdu 4604 动态规划
- d008: 求两数的整数商 和 商
- UVA 12263 Rankings(拓扑排序)
- 国内Android应用推广的六大主流方式
- Linux C编程一站式学习读书笔记——socket编程
- udp接收
- 如何使用 IDEA 创建项目并且上传到 GitHub
- UVALive - 4222
- linux下添加逻辑分区并挂载(手动和自动方式)
- 用C#创建一个窗体,在构造函数里面写代码和在from_load事件里面写代码有什么不同?
热门文章
- standard_init_linux.go:207: exec user process caused ";no such file or directory";
- 记一个AbstractMethodError
- weed3-1.hello world
- [认证 &; 授权] 3. 基于OAuth2的认证(译)
- WebShell代码分析溯源(九)
- GitLab基本设置-新增用户
- 【转载】C#中decimal保留2位有效小数
- FS-Cache 调研
- mongodb基本安装
- THUWC2019酱油记