如何使用`setr​​limit`来限制内存使用? RLIMIT_AS 杀得太快; RLIMIT_DATA、RLIMIT_RSS、RLIMIT_STACK 根本不杀死

Posted

技术标签:

【中文标题】如何使用`setr​​limit`来限制内存使用? RLIMIT_AS 杀得太快; RLIMIT_DATA、RLIMIT_RSS、RLIMIT_STACK 根本不杀死【英文标题】:How do I use `setrlimit` to limit memory usage? RLIMIT_AS kills too soon; RLIMIT_DATA, RLIMIT_RSS, RLIMIT_STACK kill not at all 【发布时间】:2017-02-06 22:20:41 【问题描述】:

我正在尝试使用setrlimit 来限制我在 Linux 系统上的内存使用,以阻止我的进程使机器崩溃(我的代码使高性能集群上的节点崩溃,因为错误导致内存消耗超过 100 GiB)。我似乎找不到要传递给setrlimit 的正确资源;我认为它应该是驻留的,cannot be limited with setrlimit,但我对驻留、堆、堆栈感到困惑。在下面的代码中;如果我只取消注释RLIMIT_AS,代码将在numpy.ones(shape=(1000, 1000, 10), dtype="f8") 处以MemoryError 失败,即使该数组应该只有80 MB。如果我只取消注释 RLIMIT_DATARLIMIT_RSSRLIMIT_STACK 两个数组都会成功分配,即使总内存使用量为 2 GB,或者是所需最大值的两倍。

我想让我的程序在尝试分配过多 RAM 时立即失败(无论如何)。为什么RLIMIT_DATARLIMIT_RSSRLIMIT_STACKRLIMIT_AS 都没有按照我的意思执行,传递给setrlimit 的正确资源是什么?

$ cat mwe.py 
#!/usr/bin/env python3.5

import resource
import numpy

#rsrc = resource.RLIMIT_AS
#rsrc = resource.RLIMIT_DATA
#rsrc = resource.RLIMIT_RSS
#rsrc = resource.RLIMIT_STACK

soft, hard = resource.getrlimit(rsrc)
print("Limit starts as:", soft, hard)

resource.setrlimit(rsrc, (1e9, 1e9))

soft, hard = resource.getrlimit(rsrc)
print("Limit is now:", soft, hard)
print("Allocating 80 KB, should certainly work")
M1 = numpy.arange(100*100, dtype="u8")

print("Allocating 80 MB, should work")
M2 = numpy.arange(1000*1000*10, dtype="u8")

print("Allocating 2 GB, should fail")
M3 = numpy.arange(1000*1000*250, dtype="u8")

input("Still here…")

RLIMIT_AS 行未注释的输出:

$ ./mwe.py 
Limit starts as: -1 -1
Limit is now: 1000000000 -1
Allocating 80 KB, should certainly work
Allocating 80 MB, should work
Traceback (most recent call last):
  File "./mwe.py", line 22, in <module>
    M2 = numpy.arange(1000*1000*10, dtype="u8")
MemoryError

在任何其他未注释的情况下运行时的输出:

$ ./mwe.py 
Limit starts as: -1 -1
Limit is now: 1000000000 -1
Allocating 80 KB, should certainly work
Allocating 80 MB, should work
Allocating 2 GB, should fail
Still here…

在最后一行,top 报告我的进程正在使用 379 GB VIRT、2.0 GB RES。


系统详情:

$ uname -a
Linux host.somewhere.ac.uk 2.6.32-573.3.1.el6.x86_64 #1 SMP Mon Aug 10 09:44:54 EDT 2015 x86_64 x86_64 x86_64 GNU/Linux

$ cat /etc/redhat-release 
Red Hat Enterprise Linux Server release 6.7 (Santiago)

$ free -h
             total       used       free     shared    buffers     cached
Mem:          2.0T       1.9T        37G       1.6G       3.4G       1.8T
-/+ buffers/cache:        88G       1.9T 
Swap:         464G       4.8M       464G 

$ python3.5 --version
Python 3.5.0

$ python3.5 -c "import numpy; print(numpy.__version__)"
1.11.1

【问题讨论】:

Setting stacksize in a python script的可能重复 尝试在Stack *** 修正后设置rlimit_stack 可能会导致失败或相关问题。另请参阅红帽 Issue 1463241 【参考方案1】:

唉,你的问题我没有答案。但我希望以下内容可能会有所帮助:

您的脚本在我的系统上按预期工作。请分享您的确切规格,可能是 Linux 发行版、内核甚至 numpy 存在已知问题... RLIMIT_AS 应该没问题。正如here 解释的那样,这应该限制进程使用的整个虚拟内存。而虚拟内存包括所有:交换内存、共享库、代码和数据。更多详情here。

您可以在脚本中添加以下函数(从this answer 采用)随时检查实际虚拟内存使用情况:

def peak_virtual_memory_mb():
    with open('/proc/self/status') as f:
        status = f.readlines()
        vmpeak = next(s for s in status if s.startswith("VmPeak:"))
        return vmpeak
一般建议,禁用交换内存。根据我使用高性能服务器的经验,它弊大于利。

【讨论】:

我添加了一些系统细节。我需要添加更多吗? top 报告我正在使用 379 GB 虚拟内存。我不知道为什么,但它可能解释了为什么RLIMIT_AS 版本会提前失败。注意:我只是此服务器上的用户,无法禁用交换内存。 是的,379GB确实很奇怪,这或许可以解释早期的失败。这台机器运行什么 Linux 风格?你在内存分配前后有没有试过print peak_virtual_memory_mb()?顺便说一句,最好不要在公共网站上分享主机名:) @它是 Redhat Enterprise Linux(见编辑)。我不确定如何打印峰值虚拟内存。 好吧。在 Redhat 上没有找到任何东西。有关打印 VM 的代码,请参见我上面的答案。或者您可以在您的脚本上运行内存分析器 - pypi.python.org/pypi/memory_profiler。我担心我没有更多的想法:)

以上是关于如何使用`setr​​limit`来限制内存使用? RLIMIT_AS 杀得太快; RLIMIT_DATA、RLIMIT_RSS、RLIMIT_STACK 根本不杀死的主要内容,如果未能解决你的问题,请参考以下文章

Linux 如何限制内存的使用

Docker 容器达到 Memory Limit 后的行为

Oracle12c 新特性:限制PGA使用内存的大小

增加内存限制 Composer 不起作用

处理大型数据集和内存限制 [关闭]

如何使用大小限制包?