我们有一个进程在最近几周发生了一次性内存泄漏,导致它消耗了我们 RHEL 7 机器上的所有内存
我们现在希望对此设置限制,以便它永远不会超过一定数量
我们使用 ulimit -v 设置来设置这个数量(因为 -m 设置不起作用)
因此,我想知道这是否足够,还是我们还需要一种限制物理内存的方法?如果是这样,最好的方法是什么?
如果虚拟内存总是随着物理内存增长,那么 -v 本身就足够了
关于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.
| 归档时间: |
|
| 查看次数: |
4421 次 |
| 最近记录: |