前言
ulimit 主要是用来限制进程对资源的使用情况的,它支持各种类型的限制,常用的有:
- 内核文件的大小限制
- 进程数据块的大小限制
- Shell进程创建文件大小限制
- 可加锁内存大小限制
- 常驻内存集的大小限制
- 打开文件句柄数限制
- 分配堆栈的最大大小限制
- CPU占用时间限制用户最大可用的进程数限制
- Shell进程所能使用的最大虚拟内存限
源于一次粗心大意, 编写的程序忘记了关闭打开的文件, 导致文件打开失败, 失败的原因是打开的文件太多
测试代码
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <csignal>
#include <errno.h>
void signt_handle(int s){
printf("%s\n", __FUNCTION__);
exit(0);
}
int main(int argc, char** argv) {
printf("[I]%s.START....\n", __FUNCTION__);
std::signal(SIGINT, signt_handle);
bool close = false;
int num = 0;
for(int i = 0; i < argc; i ++){
printf("[D]%s arg:%s\n", __FUNCTION__, argv[i]);
char* val = nullptr;
if((val = strstr(argv[i], "num=")) != nullptr){
num = atoi(val + 4);
}else if(strcmp(argv[i], "close") == 0){
close = true;
}
}
for(int i = 0; i < num; i ++){
FILE* fp = fopen("/bootTime", "r");
if(fp != nullptr){
printf("[D]%s.open %d\r", __FUNCTION__, i);
//open success.
}else{
printf("[E]%s open %d failed: %d(%s)!\r", __FUNCTION__, i, errno, strerror(errno));
}
if(close)fclose(fp);
}
printf("\n");
char c = getc(stdin);
//while((c = getc(stdin)) != 'q');
printf("[I]%s.FINISH....\n", __FUNCTION__);
}
报错 open failed: 24(Too many open files)
查看系统限制:
//查看所有的限制信息
$userdata# ulimit -a
real-time non-blocking time (microseconds, -R) unlimited
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 63277
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 63277
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
//查看文件打开个数信息
$userdata# ulimit -n
1024
系统的文件打开数量限制为1024, 简单测试打开1025个文件:
# /userdata/test_ulimit num=1025
[I]main.START....
[D]main arg:/userdata/test_ulimit
[D]main arg:num=1025
[E]main open 1024 failed: 24(Too many open files)!
q
[I]main.FINISH....
再进程未结束是, 可以从lsof 可以看出当前进程打开的文件:
$ adb shell lsof | grep test_
16363 /userdata/test_ulimit 0 /dev/console
16363 /userdata/test_ulimit 1 /dev/console
16363 /userdata/test_ulimit 2 /dev/console
16363 /userdata/test_ulimit 3 /bootTime
16363 /userdata/test_ulimit 4 /bootTime
//中间省略N行.
16363 /userdata/test_ulimit 1026 /bootTime
16363 /userdata/test_ulimit 1027 /bootTime
如何解决
- 及时关闭文件, 避免文件数量超出, 上面的程序增加了close参数, 用于及时关闭文件
- 修改系统文件打开数量的限制:
ulimit -n 2048
RK3588 buildroot 修改默认配置
1.无效的尝试
-
/etc/security/limits.conf
# 添加如下的行 * soft noproc 11000 * hard noproc 11000 * soft nofile 4100 * hard nofile 4100
-
/etc/init.d/rcS
在这个启动脚本中,你可以将
ulimit -n 4096
放在for
循环之前,确保在启动所有init.d
脚本之前设置ulimit
。这样可以确保在执行任何其他初始化操作之前设置了最大打开文件数。所以你可以将
ulimit -n 4096
添加在for
循环之前,类似这样:#!/bin/sh # Set maximum number of open files ulimit -n 4096 # Start all init scripts in /etc/init.d executing them in numerical order. for i in /etc/init.d/S??* ;do # Ignore dangling symlinks (if any). [ ! -f "$i" ] && continue case "$i" in *.sh) # Source shell script for speed. ( trap - INT QUIT TSTP set start . $i ) ;; *) # No sh extension, so fork subprocess. $i start ;; esac done
这样做可以确保在执行其他初始化脚本之前设置了ulimit
。
- 有效的修改:
-
/etc/profile
/etc/profile
是一个系统范围的 Shell 配置文件,用于设置系统中所有用户的环境变量和执行一些全局的 Shell 初始化任务。这个文件通常用于 Bourne-compatible shells(例如 Bash、Dash、Korn shell 等)。当用户登录时,Shell 会首先读取
/etc/profile
文件,然后再读取用户的个人配置文件(如~/.bash_profile
或~/.profile
)。因此,/etc/profile
文件中的设置将影响到所有用户的登录 shell。在
/etc/profile
文件中,你可以设置系统范围的环境变量、导入全局的 Shell 函数、执行一些初始化命令等。这对于配置系统范围的默认行为和环境非常有用,例如设置全局的 PATH 变量、umask 值、语言环境等。需要注意的是,修改
/etc/profile
文件需要管理员权限,因为它是系统级别的配置文件。任何对该文件的更改都会影响到整个系统的行为,因此需要小心谨慎地修改。 -
/etc/bash.bashrc
/etc/bash.bashrc
是另一个系统范围的 Bash Shell 配置文件,它与/etc/profile
类似,但是它是针对 Bash Shell 的。与/etc/profile
一样,/etc/bash.bashrc
文件也是在用户登录时被执行的。与用户级别的
.bashrc
文件类似,/etc/bash.bashrc
文件通常包含了一些 Bash Shell 的配置和初始化命令,用于设置系统范围的 Shell 环境。这些设置通常适用于所有的 Bash Shell 用户。在
/etc/bash.bashrc
文件中,你可以设置系统范围的 Bash Shell 环境变量、定义全局的 Bash 函数、启用或禁用 Bash Shell 的特性等。需要注意的是,
/etc/bash.bashrc
文件是在 Bash Shell 启动时执行的,而不是用户登录时执行的,因此它可能不会像/etc/profile
那样被所有类型的 Shell 执行。如果系统中有其他类型的 Shell 用户,它们可能不会执行/etc/bash.bashrc
文件中的设置。 -
针对特定进程修改其打开文件的个数限制(来自GPT, 未验证)
要针对特定进程修改其打开文件的个数限制(ulimit),你可以使用
ulimit
命令结合sudo
进行修改。但需要说明的是,ulimit
命令通常只能影响当前 shell 及其子进程的限制,对已经运行的进程并不生效。因此,如果你希望修改已经在运行的进程的文件打开数限制,你需要重新启动该进程或者重新登录用户以应用新的限制。下面是修改某个进程打开文件数限制的一般步骤:
-
确定进程ID(PID):首先,你需要确定你想要修改的进程的PID。你可以使用
ps
命令或者pidof
命令来查找进程的PID。例如,如果你想要修改PID为1234的进程的限制,你可以执行:ps aux | grep <进程名>
或者
pidof <进程名>
-
使用
sudo
修改限制:一旦你有了PID,你可以使用sudo
命令和ulimit
命令来修改限制。例如,要将打开文件数限制修改为4096,你可以执行:sudo prlimit --pid <PID> --nofile=4096:4096
或者
sudo ulimit -n 4096 -p <PID>
-
验证更改:修改限制后,你可以使用
ulimit -a
命令检查更改是否已生效。此外,你也可以通过查看进程的/proc/<PID>/limits
文件来验证限制是否已应用。
请注意,
ulimit
命令对不同的操作系统可能会有些许差异,而prlimit
命令在一些系统上可能需要安装额外的软件包。确保在执行任何修改之前仔细阅读命令的文档以及系统的相关文档。 -
- 修改buildroot 源码默认配置为9999
$ git diff buildroot/system/skeleton/etc/profile
diff --git a/buildroot/system/skeleton/etc/profile b/buildroot/system/skeleton/etc/profile
index f2907e417..a6f44c6c2 100755
--- a/buildroot/system/skeleton/etc/profile
+++ b/buildroot/system/skeleton/etc/profile
@@ -25,3 +25,6 @@ for i in /etc/profile.d/*.sh ; do
fi
done
unset i
+
+ulimit -HSn 9999
清除, 编译!
参考
- ulimit - Set or display resource limits
- ulimit最详解
- linux ulimit作用
- [SOLVED] How to set ulimit at user level?
- /etc/security/limits.conf not applied
- ulimit 命令详解
- ulimit命令说明与用法
- 关于skeleton
在 Buildroot 中,skeleton 指的是包含基本文件和目录的目录树,这些文件和目录是运行最小化 Linux 系统所需的基本组件。它通常包括以下文件:
/bin
和/sbin
:这些目录包含必要的可执行程序,例如bash
、ls
、cp
和mv
。/etc
:此目录包含各种系统服务的配置文件。/lib
和/usr/lib
:这些目录包含应用程序使用的库。/proc
:此目录包含有关正在运行的进程的信息。/sys
:此目录包含有关系统硬件的信息。/dev
:此目录包含设备节点,用于访问硬件设备。/tmp
:此目录用于临时文件。/usr
:此目录包含用户安装的程序和文件。skeleton 通常从模板创建,该模板可以自定义以包含特定于目标系统的其他文件和目录。然后将 skeleton 复制到根文件系统,该文件系统在引导期间挂载在
/
上。Buildroot skeleton 是创建自定义嵌入式 Linux 系统的有用起点。它提供了一个基本框架,可以轻松扩展以满足项目的特定需求。
使用 Buildroot 中的 skeleton 有以下一些好处:
- *节省时间和精力。**您无需手动创建运行最小化 Linux 系统所需的所有文件和目录。
- *确保根文件系统一致且组织良好。**skeleton 为根文件系统提供了一个标准布局,这使得更容易找到文件和目录。
- *轻松添加自定义包。**只需将自定义包复制到适当的目录即可轻松将其添加到 skeleton 中。
如果您正在使用 Buildroot 开发嵌入式 Linux 系统,我建议使用 skeleton。它将节省您的时间和精力,并使其更容易创建满足您特定需求的系统。
以下是一些可能有用的额外资源:
- Buildroot 关于 skeleton 的文档:https://buildroot.org/downloads/manual/manual.html
- 自定义 skeleton 的示例:https://github.com/buildroot/buildroot
- 关于如何创建自定义 skeleton 的讨论:https://buildroot.org/downloads/manual/manual.html