如何使用`setrlimit`来限制内存使用? RLIMIT_AS 杀得太快; RLIMIT_DATA、RLIMIT_RSS、RLIMIT_STACK 根本不杀死
Posted
技术标签:
【中文标题】如何使用`setrlimit`来限制内存使用? 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_DATA
、RLIMIT_RSS
或 RLIMIT_STACK
两个数组都会成功分配,即使总内存使用量为 2 GB,或者是所需最大值的两倍。
我想让我的程序在尝试分配过多 RAM 时立即失败(无论如何)。为什么RLIMIT_DATA
、RLIMIT_RSS
、RLIMIT_STACK
和RLIMIT_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。我担心我没有更多的想法:)以上是关于如何使用`setrlimit`来限制内存使用? RLIMIT_AS 杀得太快; RLIMIT_DATA、RLIMIT_RSS、RLIMIT_STACK 根本不杀死的主要内容,如果未能解决你的问题,请参考以下文章