离堆、本地堆、直接内存和本地内存有什么区别?

37
最近我在学习JVM内部时遇到了这些概念。我知道Stack Overflow上已经有很多关于它们的单独问题,但我仍然无法理解它们之间的关系或者说它们到底是什么。
下面是我的理解:
1. Native memory 指的是普通JVM堆外的内存区域,但仍然在操作系统为JVM进程预留的用户空间内存总量之内(例如32位Windows上默认为2GB)。JVM保留此空间来存储一些内部数据,如永久代/方法区等。
2. Direct memory 意味着通过 java.nio.DirectByteBuffer 使用本机内存。
3. Native heap 意味着你可以通过 unsafe.allocateMemory 或在JNI代码中直接使用 malloc 来使用本机内存。
4. Off-heap 与本机内存相同。
另外一个问题是,是否可能在 JVM 进程的总内存空间(32位操作系统上为4GB)之外直接分配内存?
请指出我的理解错误,并尽可能清晰地描述它们。
3个回答

39

1) 堆内存:JVM进程中用于保存Java对象的内存,并由JVM的垃圾回收器维护。

2) 本机内存/非堆内存:分配在进程地址空间中的内存不在堆内存中,因此不会被Java垃圾回收器释放。

3) 直接内存:类似于本机内存,但还意味着硬件中的底层缓冲区正在共享。例如,网络适配器或图形显示器中的缓冲区。这里的目标是减少同一字节在内存中被复制的次数。

最后,根据操作系统的不同,可以通过Unsafe alloc和/或通过内存映射文件进行额外的本机分配(分配内存地址空间)。内存映射文件特别有趣,因为它可以轻松地分配比机器当前具有的物理内存更多的内存。还要注意,总地址空间限制受使用的指针大小的限制,32位指针不能超出4GB。 。


4
我很难理解Java和操作系统提供的内存分段。现在,操作系统将进程的地址空间分成多个段,如堆栈数据文本,同样,JVM进程内存也会有这些由操作系统提供的分段。当JVM开始执行JAVA程序时,它(JVM)再次向Java程序提供类似的分段。现在我真的很困惑这两种类型的内存分段,一种是由操作系统提供,另一种是由JVM提供给Java程序的。你能帮我理解吗? - Ankush G

1
"还有一个问题,是否可能直接分配内存到JVM进程保留的总内存空间(32位操作系统上的4GB)之外?"
"在32位操作系统上,一个进程的虚拟地址空间限制为4GB。4字节指针无法寻址超过这个范围之外的内存。"
"你唯一能做的就是打开一个大文件,并通过有限数量的内存映射缓冲区与其交互,根据需要进行映射和释放,并希望操作系统页面缓存将它们保留在物理内存中。"
"如果你需要超过2GB的内存,你真的应该使用64位操作系统和JVM。"

1
许多在JVM上运行的高性能服务器应用程序,如Apache Cassandra,使用离堆内存来提高服务器性能。它曾经将大部分数据结构存储在堆上,但在最近的版本中,它已被存储在离堆内存中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接