"setrlimit()"不影响正在运行的进程

"setrlimit()" is not affecting the running process

本文关键字:运行 进程 影响 setrlimit      更新时间:2023-10-16

我正在尝试模拟 Linux 中进程的错误场景,该进程的堆不足以在C++ Linux 应用程序中分配内存。但是,即使我使用"setrlimit"来减少进程可用的堆内存,堆内存仍然被成功分配。

struct rlimit the_limit = { 1, 1 };
if (-1 == setrlimit(RLIMIT_DATA, &the_limit)) {
    perror("setrlimit failed");
}
try
{
   char *n = new char[5600];
   if (n==NULL)
   {
      cout <<"nAllocation Failuren";
   }
}
catch (std::bad_alloc& ba)
{
   std::cerr << "bad_alloc caught: " << ba.what() << 'n';
}

大多数C++标准库(包括 g++ 提供的库(都以预分配的一些堆内存开始。5600 是一个小请求,因此,在我的 Linux 系统上,它从预分配的内存中得到满足,如所证明的那样从strace

修改后的示例:

#include <stdio.h>
#include <sys/resource.h>
int main()
{
    struct rlimit the_limit = { 1, 1 };
    if (-1 == setrlimit(RLIMIT_DATA, &the_limit)) { perror("setrlimit failed"); }
    puts("ALLOC");
    #if __cplusplus
    try { char *n = new char[5600]; } catch (...) { perror("alloc failure"); }
    #else
    { char *n = malloc(1); if(!n) perror("alloc failure"); }
    #endif
}

示例的跟踪结束:

...
write(1, "ALLOCn", 6ALLOC
)                  = 6
exit_group(0)                           = ?

要么增加请求大小,例如在我的情况下至少增加到 1<<16 ,要么切换到普通 C,都会导致分配请求从操作系统提供服务,然后限制确实适用:

使用1<<16分配请求结束跟踪:

write(1, "ALLOCn", 6ALLOC
)                  = 6
brk(0x561bcc5d4000)                     = 0x561bcc5b2000
mmap(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = -1 ENOMEM (Cannot allocate memory)
dup(2)                                  = 3
fcntl(3, F_GETFL)                       = 0x2 (flags O_RDWR)
fstat(3, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 14), ...}) = 0
write(3, "alloc failure: Cannot allocate m"..., 38alloc failure: Cannot allocate memory
) = 38
close(3)                                = 0
exit_group(0)                           = ?

请注意,通用分配器实现通常使用 sbrk 和/或 mmap直接从操作系统获取内存,并且您可以从setrlimit手册页中收集内存,RLIMIT_DATA仅适用于mmap支持的分配,前提是您使用的是 Linux>= 4.7。