设置 ulimit -v 是否足以避免内存泄漏

DJ1*_*180 4 linux rhel ulimit

我们有一个进程在最近几周发生了一次性内存泄漏,导致它消耗了我们 RHEL 7 机器上的所有内存

我们现在希望对此设置限制,以便它永远不会超过一定数量

我们使用 ulimit -v 设置来设置这个数量(因为 -m 设置不起作用)

因此,我想知道这是否足够,还是我们还需要一种限制物理内存的方法?如果是这样,最好的方法是什么?

如果虚拟内存总是随着物理内存增长,那么 -v 本身就足够了

Yur*_*ruk 5

关于ulimit工作原理的一些描述:

ulimit有处理setrlimit和getrlimit系统调用。通过strace-ing of bash 进程(ulimit是 的组件bash)很容易确保。我设置了 1024kb 的max memory size:

$ ulimit -m 1024
Run Code Online (Sandbox Code Playgroud)

在另一个控制台中:

$ strace -p <my_bash_pid>
. . .
getrlimit(RLIMIT_RSS, {rlim_cur=1024*1024, rlim_max=1024*1024}) = 0
setrlimit(RLIMIT_RSS, {rlim_cur=1024*1024, rlim_max=1024*1024}) = 0
. . . 
Run Code Online (Sandbox Code Playgroud)

setrlimit手册页接下来写关于RLIMIT_RSS:

RLIMIT_RSS指定进程驻留集的限制(以页为单位)(驻留在 RAM 中的虚拟页数)。此限制仅在Linux 2.4.x、x < 30 中有效,并且仅影响对 指定 MADV_WILLNEED 的madvise(2) 的调用。

madvicesyscall 只是对内核的建议,内核可能会忽略此建议。甚至bash关于ulimit写以下的手册页:

-m 最大驻留集大小(许多系统不遵守此限制)

这就是为什么-m不起作用的原因。

关于-v选项:

我设置了 1024 kb 的虚拟内存:

$ ulimit -v 1024
Run Code Online (Sandbox Code Playgroud)

在另一个控制台中:

$ strace -p <my_bash_pid>
. . .
getrlimit(RLIMIT_AS, {rlim_cur=RLIM64_INFINITY, rlim_max=RLIM64_INFINITY}) = 0
setrlimit(RLIMIT_AS, {rlim_cur=1024*1024, rlim_max=1024*1024}) = 0
. . .
Run Code Online (Sandbox Code Playgroud)

setrlimit手册页接下来写关于RLIMIT_AS:

RLIMIT_AS进程的虚拟内存(地址空间)的最大大小(以字节为单位)。此限制会影响对brk(2)、mmap(2)和 mremap(2) 的调用,在超过此限制时会失败并显示错误 ENOMEM。此外,自动堆栈扩展也会失败(如果没有通过 sigaltstack(2) 提供可用的替代堆栈,则会生成一个 SIGSEGV 来终止进程)。由于该值为 long,因此在具有 32 位 long 的机器上,此限制最多为 2 GiB,或者此资源是无限的。

程序由 3 个段(数据、代码、堆栈)组成,构成虚拟程序存储空间。

  • 代码段是常量并且包含程序指令。

  • 数据段由以下控制:

    brksyscall 调整程序的数据段(虚拟内存的一部分)的大小。

    mmap 系统调用将文件或设备映射到进程的虚拟内存。

    许多程序通过调用malloc从堆(数据段的一部分)分配内存的C 库 ( ) 中的标准函数来分配内存(直接或间接)。malloc通过调用brk系统调用来调整数据段的大小。

  • 堆栈存储函数变量(变量在从堆栈分配期间占用内存)。

因此,这就是该-v选项适合您的原因。

如果-v足以完成您的任务,那么就没有理由去做其他事情,这就足够了。


如果您想控制进程的大量特定内存功能(内存压力、交换使用、RSS 限制、OOM 等),我建议您使用cgroups 内存功能。

如果您的应用程序是服务,我建议您使用systemd 切片功能,因为它最方便地控制和限制cgroups由systemd.