当大型父进程的子分支关闭时,如何防止 Perl 消耗大量内存?

How do I keep Perl from consuming tons of memory when child forks of a large parent process shut down?

上下文:

我有一个在 Linux 上运行的多分支 Perl (5.16) 进程。父分支加载了大量的 Perl 代码(通过 use/require)并分配了大量的数据结构(数 GB)。然后它会创建许多子叉子,所有子叉子都并行工作。这样做是为了减少进程运行时的内存占用,因为 fork() 的写时复制特性意味着子进程可以使用父进程拥有的数据,而无需各自维护自己的大内存映像。

问题:

在我尝试关闭进程组之前,所有这些都工作正常。当我中断父进程(信号传播到所有子进程)时,服务器上的内存 运行 代码立即填满,它开始交换,服务器上的其他进程逐渐停止。当写时复制分支关闭时,Perl 似乎试图重新分配父进程中声明的所有内存,以便它可以将其标记为 free 或其他东西。

问题:

如何防止这种关机时膨胀的情况发生?有什么方法可以告诉子叉只尝试遍历和回收那些叉分配的内存吗?

内存页的分配是由于退出时变量的释放。这是调用析构函数所必需的。

调用 POSIX::_exit() 将立即退出,跳过每个变量的重新分配,也跳过析构函数的调用。

我接受了@ikegami 的回答,因为它直接回答了问题。

我发布这个是因为我的"solution"(确实是一种优化部分问题的方法)可能对其他人有用。

我的案例的最终修复是范式转变:我意识到问题不在于 any Perl 进程在 fork 关闭时占用了大量内存,而是我有 这么多 Perl 进程在关闭时 同时 消耗内存。

当我的parent进程得到"shutdown"指令后,它立即向它的所有children发送了一个"shutdown"消息,它们都完成了它们的工作正在或多或少同时关闭。数十到数百个 child 进程同时关闭,内存开销太大。

解决方法是让关闭成为一个 two-phase 进程:首先,parent 进程向其所有 children 发送一条 "stop what you're doing" 消息,以便业务逻辑在可预测的时间停止 运行。它以非常快速的循环将该消息发送给 once/in 的所有 children。然后,它一次关闭 children 。它向每个 child 发出一个中断,调用 waitpid 直到它完成,然后继续下一个

这样,worst-case shutdown-induced 内存占用(p 代表 pre-fork 内存占用,f 代表 child forks) 是 2p,而不是 fp.

2p 内存消耗仍然是 unacceptably-high 成本的情况下,此解决方案将不起作用。

添加了两个优化:timeout/forceful-kill 检查 stubborn/broken children 和 child-shutdowns 之间的条件 sleeps 如果前一个 child 的关闭迫使系统开始交换。 sleeps 给系统时间 breathe/get 个页面交换。

同样,这是对问题的优化,而不是答案。真正的答案是@ikegami 的。