JVM内存分段分配

6

好的,我有一个关于JVM内存段的问题, 我知道每个JVM都会选择以稍微不同的方式实现这个功能,但它是一个整体概念,应该在所有JVM中保持一致。

对于在运行时不使用虚拟机执行的标准C/C++程序,具有四个内存段:代码、栈、堆和数据。在运行时,所有这些内存段都由操作系统自动分配。

然而,当一个JVM执行Java编译程序时,在运行时它有5个内存段:

方法区 / 堆 / Java栈 / PC寄存器 / 本地栈

我的问题是,谁分配和管理这些内存段? 操作系统不知道正在运行的Java程序,并认为它是作为计算机上常规程序运行的JVM的一部分。JIT编译和Java栈使用这些操作需要运行时内存分配。我没有理解的是JVM如何将其内存划分为这些内存段。它肯定不是由操作系统完成的,而且这些内存段(例如Java栈)必须是连续的才能工作,因此如果JVM程序简单地使用诸如malloc之类的命令来接收最大堆内存大小并将该内存划分为段,则无法得到连续的内存。我希望有人能帮助我搞清楚这一点,我的想法都混乱了...

1个回答

5
当JVM启动时,它有成百上千个内存区域。例如,每个线程都有一个堆栈以及一个线程状态区域。每个共享库和jar文件都有一个内存映射。注意:Java 64位不像16位应用程序那样使用段。
谁分配和管理这些内存段?
所有内存映射/区域都由操作系统分配。
操作系统不知道正在运行的Java程序,并认为它是作为计算机上常规程序运行的JVM的一部分。
JVM作为常规程序运行,但是内存分配使用与普通程序相同的机制。唯一的区别在于,在Java中,对象分配由JVM管理,但这是唯一以这种方式工作的区域。
JIT编译在正常的操作系统线程中进行,每个Java堆栈都是正常的线程堆栈。
这些操作需要运行时内存分配。
大多数情况下,它使用malloc和free以及map和unmap 我无法理解的是JVM如何将其内存划分为这些内存段。
它没有这样做。堆只适用于Java对象。最大堆大小不是最大内存使用量,而仅是您可以同时拥有的最大对象数量。
这绝对不是由操作系统完成的,那些内存段(例如Java堆栈)必须是连续的才能工作。
您是正确的,它们需要在虚拟内存中连续,但操作系统会执行此操作。至少在Linux上,不使用段,只使用一个32位或64位内存区域。
因此,如果JVM程序只是使用诸如malloc之类的命令来接收堆内存的最大大小并将该内存划分为段,则我们无法保证连续的内存。
堆被分成代或在G1中分成多个内存块,但这仅适用于对象。
垃圾收集器通过复制内存进行碎片整理,或采取措施尝试减少它以确保有足够的连续内存来分配任何对象。
总之,JVM像其他程序一样运行,只是当Java代码运行时,其对象在受管理的内存区域中分配。除此之外,所有其他内存区域都像在C程序中一样运行,因为JVM是C / C ++程序。

2
好的回答,我也想写一个,但不确定如何确切表达。简而言之,你最后一句话总结了我想说的:所有其他内存区域的功能都像在C程序中一样,因为JVM是一个C / C++程序。 - Markus Weninger
@DrPrItay 那个“one thing”是什么? - Peter Lawrey
@PeterLawrey 啊,我的问题是我在很多地方读到过Java堆栈不一定是使用连续内存实现的线程堆栈,一个像C/C++程序的常规堆栈会是连续的,在Java中,我读到堆栈帧的实现有点不同。 - DrPrItay
@DrPrItay Java堆栈在字节码中的表现是不同的,因为它们并非基于它们使用的空间。然而,在运行时,HotSpot JVM使用常规本地堆栈来实现这一点。 - Peter Lawrey
@PeterLawrey 这真是一篇非常好的、精确的解释。非常感谢。我已经苦苦思考这些问题很长时间了。我有一个问题。在执行Java程序时,只有堆由JVM管理,而其他段如栈、数据等则由操作系统管理,那么JVM如何处理字节码中的“方法”调用,即在Java代码中。因为方法调用/处理需要栈段,而操作系统不知道Java方法,它只知道用C代码编写的JVM方法调用。请帮我解答这个问题! - Ankush G
显示剩余2条评论

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