Java Runtime.exec() 在内存方面从哪个 Linux 内核/libc 版本是安全的?
在工作中,我们的目标平台之一是运行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()进行写入复制?