有时候发现线上运行的程序没有修改 ulimit -n ,导致文件描述符不够用,但是又不能随便重启服务,或者碰到运行中的程序可能不定时会 segment fault ,但是由于没 ulimit -c ,无法得到 core 文件调试。但是 linux 的 ulimit 命令只对当前会话有效,已经启动的进程是没法用这个命令修改限制的。这时候如果能动态修改进程的 rlimit 就会方便很多。linux 内核版本 2.6.36 以后,多了一个 prlimit 调用,可以实现动态修改某个进程的 rlimit。
例如,这个 C 写的小程序就可以放开指定进程的 core dump 限制。
#include <stdio.h> #include <sys/time.h> #include <sys/resource.h> #include <sys/types.h> int main(int argc, char** argv) { pid_t pid; struct rlimit new_limit; int result; if (argc < 2) { return 1; } pid = atoi(argv[1]); new_limit.rlim_cur = RLIM_INFINITY; new_limit.rlim_max = RLIM_SAVED_MAX; result = prlimit(pid, RLIMIT_CORE, &new_limit, NULL); return result; }
rlimit 相关常量在 /usr/include/bits/resource.h 中有定义。这里 prlimit 的具体定义也可以通过 man 2 prlimit 查看文档。
如果有幸可以用上 util-linux 2.21 以上版本(http://www.kernel.org/pub/linux/utils/util-linux/),那么直接就会有一个 prlimit 命令可用。那就非常方便了。
但是如果内核版本较低,没有这功能又怎么办呢?其实还可以通过万能的 gdb 钩进进程调用 setrlimit 来实现。于是,可以包装一个脚本出来:
#!/bin/bash f="0" while getopts ":c:d:e:f:i:l:m:n:p:q:r:s:t:u:v:x" opt; do if [ "$f" == "1" ]; then echo "too many arguments" >&2; exit 1 fi f="1" v="$OPTARG" case $opt in c) r=4 ;; # RLIMIT_CORE core file size d) r=2 ;; # RLIMIT_DATA data seg size e) r=13 ;; # RLIMIT_NICE scheduling priority f) r=1 ;; # RLIMIT_FSIZE file size i) r=11 ;; # RLIMIT_SIGPENDING pending signals l) r=8 ;; # RLIMIT_MEMLOCK max locked memory m) r=5 ;; # RLIMIT_RSS max memory size n) r=7 ;; # RLIMIT_NOFILE open files q) r=12 ;; # RLIMIT_MSGQUEUE POSIX message queues r) r=14 ;; # RLIMIT_RTPRIO real-time priority s) r=3 ;; # RLIMIT_STACK stack size t) r=0 ;; # RLIMIT_CPU cpu time u) r=6 ;; # RLIMIT_NPROC max user processes v) r=9 ;; # RLIMIT_AS virtual memory x) r=10 ;; # RLIMIT_LOCKS file locks ?) echo "bad argument $opt" >&2; exit 1 ;; esac done shift $(($OPTIND - 1)) if echo "$v" | grep -q -E "^\-?[0-9]+$"; then true else echo "bad rlimti value $v" >&2 exit 2 fi if [ `echo "$v==-1 || ($v>=0 && $v<1048576)"|bc` == '0' ];then echo "bad rlimti value $v" >&2 exit 2 fi pid=$1 bin=`readlink /proc/$pid/exe` if [ -z "$bin" ]; then echo "process $pid not found" >&2 exit 3 fi cmd=' set $rlim=&{-1ll,-1ll} print getrlimit('$r',$rlim) set *$rlim[0]='$v' print setrlimit('$r',$rlim) quit ' result=`echo "$cmd" | gdb $bin $pid 2>/dev/null | grep '(gdb) \$2 ='` result="${result##*= }" exit $result
如
sudo ./rlimit.sh -c -1 12345
就可以 12345 放开进程的 core dump
参数同 ulimit ,-1 表示 unlimited。不过用这种方法,只能调整 soft rlimit ,而且没法超过原有的 hard rlimit。
修改以后,可以通过 cat /proc/<pid>/limits 查看效果
补充(感谢zolker):
对于 redhat 系,如 centos 6.2 之后可以通过
echo -n 'Max processes=10240:10240' >/proc/<pid>/limits
来修改。这里的 limit 的名称就是
cat /proc/<pid>/limits
里看到的
不错,转走