【发布时间】:2010-09-17 14:46:10
【问题描述】:
在工作中,我们的目标平台之一是运行 Linux(内核 2.6.13,基于旧 Fedora Core 的自定义发行版)的资源受限的微型服务器。该应用程序是用 Java (Sun JDK 1.6_04) 编写的。 Linux OOM 杀手配置为在内存使用量超过 160MB 时终止进程。即使在高负载期间,我们的应用程序也永远不会超过 120MB,并且与其他一些活动的本机进程一起,我们保持在 OOM 限制内。
然而,事实证明 Java Runtime.getRuntime().exec() 方法是从 Java 执行外部进程的规范方法,它有一个 particularly unfortunate implementation on Linux 导致生成的子进程(暂时)需要相同的数量由于地址空间被复制,内存作为父进程。最终结果是,一旦我们执行 Runtime.getRuntime().exec(),我们的应用程序就会被 OOM 杀手杀死。
我们目前通过让一个单独的本机程序执行所有外部命令来解决此问题,并通过套接字与该程序进行通信。这不是最佳的。
在posting about this problem online 之后,我收到一些反馈,表明这不应该发生在“较新”版本的 Linux 上,因为它们使用写时复制实现了 posix fork() 方法,大概意味着它只会复制它需要的页面在需要时修改而不是立即修改整个地址空间。
我的问题是:
- 这是真的吗?
- 这是在内核、libc 实现中还是完全在其他地方?
- 从哪个版本的内核/libc/whatever 可以使用 fork() 的写时复制?
【问题讨论】:
-
在 fork() 调用和后面的 exec() 之间需要的是 virtual,而不是 physical 内存。考虑到地址空间的大小与您的物理内存限制相比,我非常怀疑您的虚拟内存不足。
-
当然,我们并没有耗尽物理内存,但 Linux 的某些部分似乎认为我们已经耗尽了。
标签: java linux memory out-of-memory