在工作中,我们的目标平台之一是运行 Linux 的资源受限的小型服务器(内核 2.6.13,基于旧的 Fedora Core 的自定义发行版)。该应用程序是用 Java (Sun JDK 1.6_04) 编写的。Linux OOM 杀手配置为在内存使用量超过 160MB 时终止进程。即使在高负载期间,我们的应用程序也永远不会超过 120MB,并且与其他一些活动的本机进程一起,我们保持在 OOM 限制内。
然而,事实证明,Java Runtime.getRuntime().exec() 方法,从 Java 执行外部进程的规范方法,在 Linux 上有一个特别不幸的实现,导致生成的子进程(暂时)需要相同数量的由于地址空间被复制,内存作为父进程。最终结果是,一旦我们执行 Runtime.getRuntime().exec(),我们的应用程序就会被 OOM 杀手杀死。
我们目前通过让一个单独的本机程序执行所有外部命令来解决这个问题,并通过套接字与该程序通信。这不是最佳的。
在网上发布这个问题后,我得到了一些反馈,表明这不应该发生在“较新”版本的 Linux 上,因为它们使用写时复制实现了 posix fork() 方法,大概意味着它只会复制它需要的页面在需要时修改而不是立即修改整个地址空间。
我的问题是:
- 这是真的?
- 这是内核、libc 实现还是其他地方的东西?
- 从哪个版本的内核/libc/fork() 可用的写时复制?