Java 进程基本上由两个不同的堆(heap)空间组成。
- Java 堆(新的、旧的和永久空间)
- 还有所谓的原生 C 堆。
当涉及到 OutOfMemory 错误和分配失败时,上述内容常常令人困惑。
特别是在 32 位模式下,根据操作系统的不同,整个进程空间限制为 4gb 甚至 2gb。
如前所述,32 位模式下的总进程大小限制为最大 4GB。
Java 堆和 C 堆相结合,以及其他空间,例如对于库、线程等,不能超过此 4GB 限制。
因此,如果我们增加 Java 堆,例如通过将 -Xmx/-Xms 从 1.5gb 增加到 2.5gb,这将对 C 堆产生显着的副作用。
在增加之前,C 堆可以轻松增长到 2GB。
因为还剩下 4gb -1.5gb = 2.5gb。
在 Java 堆从 1.5gb 增加到 2.5gb 之后,我们只剩下 4gb 2.5gb = 1.5gb 用于所有其他空间。
包括C堆。
不幸的是,Java 堆和 C 堆需要多大完全取决于应用程序。
虽然可以显式配置 Java 堆的大小,但对于 C 堆则不能这样做。
C-heap 只是扩展,直到进程大小达到 4gb 限制。
因此,如果我们将 Java 堆配置得过大,则必须小心。
这可能并且将会导致 C 堆的分配失败。
例如。
诸如此类的消息通常意味着 C 堆已耗尽:
java.lang.OutOfMemoryError: requested 67108872 bytes for Chunk::new. Out of swap space?
请注意带有双冒号的 C++ 语法。
或者这个:
# There is insufficient memory for the Java Runtime Environment to continue. # Native memory allocation (malloc) failed to allocate 65544 bytes
在这两种情况下,C 堆都太小了。
一个解决方案是减少 Java 堆。
是的,减少!这会给 C 堆更多的扩展空间。
另一方面,我们仍然可以遇到经典的 Java.lang.OutOfMemoryErrors。
那些明确指出 Java 堆容量不足。
如我们所见,如果我们在 32 位模式下运行,Java 和 C 堆之间可能会发生冲突,这可能不太容易解决。
如果一切都失败了,那么考虑迁移到 64 位,4GB 进程大小限制将不再是一个问题。
背景信息:Hotspot Java 虚拟机 (JVM) 本身是用 C++ 编写的。
因此,所有 JVM 内部分配都只发生在 C 堆中。
例如,当 GC 开始收集 Java 堆中的死对象时,它将在本机堆中分配空间来执行其工作。
另一方面,由 Java 程序分配的所有 Java 对象都将在 Java 堆中结束。
C堆不会被触及。