最近几周,我们有一个进程发生了一次性内存泄漏,导致它耗尽了 RHEL 7 机器上的所有内存
我们现在希望对此设置限制,以便永远不会超过一定数量
我们使用 ulimit -v 设置来设置此数量(因为 -m 设置不起作用)
因此,我想知道这是否足够,还是我们还需要一种方法来限制物理内存?如果是这样,最好的方法是什么?
如果虚拟内存总是随物理内存一起增长,那么 -v 本身就足够了
答案1
关于如何工作的一些描述ulimit
:
ulimit
已处理setrlimit
和getrlimit
系统调用。通过strace
bash 进程(ulimit
是 的组成部分)很容易确保bash
。我设置了 1024kb max memory size
:
$ ulimit -m 1024
在另一个控制台中:
$ 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
. . .
setrlimit
手册页接下来写的是RLIMIT_RSS
:
RLIMIT_RSS指定进程驻留集(RAM 中驻留的虚拟页数)的限制(以页为单位)。此限制仅在以下情况下有效Linux 2.4.x,x < 30,并且只影响对 疯狂的维斯(2)指定 MADV_WILLNEED。
madvice
syscall 只是对内核的建议,内核可能会忽略此建议。甚至bash
手册页也ulimit
写了以下内容:
-m 最大驻留集大小(许多系统不遵守此限制)
-m
这就是为什么行不通的原因。
关于-v
选项:
我设置了1024 kb的虚拟内存:
$ ulimit -v 1024
在另一个控制台中:
$ 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
. . .
setrlimit
手册页接下来写的是RLIMIT_AS
:
RLIMIT_AS进程虚拟内存(地址空间)的最大大小(以字节为单位)。此限制影响调用布尔克(2),映射(2)和 重映射(2),超出此限制后会失败并出现错误 ENOMEM。此外,自动堆栈扩展也会失败(如果没有通过 sigaltstack(2) 提供可用的备用堆栈,则会生成 SIGSEGV 来终止进程)。由于该值是 long,因此在具有 32 位 long 的计算机上,此限制最多为 2 GiB,或者此资源是无限的。
程序由3个段(数据、代码、堆栈)组成虚拟程序存储空间。
代码段是常量,包含程序指令。
数据段由以下控制:
brk
系统调用调整大小数据段程序的(虚拟内存的一部分)。mmap
系统调用将文件或设备映射到进程的虚拟内存。许多程序通过调用 C 库 ( ) 中的标准函数来分配内存(直接或间接),
malloc
该函数从堆(数据段的一部分)。malloc
通过调用系统调用来调整数据段的大小brk
。堆栈存储函数变量(变量在从堆栈分配期间占用内存)。
所以,这就是为什么该-v
选项适合您。
如果-v
足以完成您的任务,那么就没有理由做其他事情,这就足够了。
如果您想控制进程的大量特定内存功能(内存压力、交换使用情况、RSS 限制、OOM 等),我建议您使用cgroup内存能力。
如果您的应用程序是服务我建议你使用系统切片功能,作为控制和限制cgroups
由systemd
.