Java 虚拟机 - 运行时数据区域


JVM 规范定义了程序执行期间所需的某些运行时数据区域。其中一些是在 JVM 启动时创建的。其他的是线程本地的,仅在创建线程时创建(并在线程销毁时销毁)。下面列出了这些 -

PC(程序计数器)寄存器

它对于每个线程来说是本地的,包含线程当前正在执行的 JVM 指令的地址。

它对于每个线程来说是本地的,并在方法调用期间存储参数、本地变量和返回地址。如果线程需要的堆栈空间超过允许的空间,则可能会发生 StackOverflow 错误。如果堆栈是动态可扩展的,它仍然会抛出 OutOfMemoryError。

它在所有线程之间共享,并包含在运行时创建的对象、类的元数据、数组等。它在 JVM 启动时创建,在 JVM 关闭时销毁。您可以使用某些标志(稍后会详细介绍)来控制 JVM 要求操作系统提供的堆量。必须注意不要要求内存太少或太多,因为它对性能有重要影响。此外,GC 管理该空间并不断删除死对象以释放空间。

方法区

该运行时区域是所有线程共用的,并且在 JVM 启动时创建。它存储每个类的结构,例如常量池(稍后详细介绍)、构造函数和方法的代码、方法数据等。JLS 没有指定该区域是否需要进行垃圾收集,因此也没有指定该区域的实现JVM 可能会选择忽略 GC。此外,这可能会也可能不会根据应用程序的需要进行扩展。JLS 对此没有任何强制要求。

运行时常量池

JVM 维护每个类/每个类型的数据结构,该结构在链接加载的类时充当符号表(其众多角色之一)。

本机方法堆栈

当线程调用本地方法时,它进入了一个新的世界,在这个世界中,Java虚拟机的结构和安全限制不再阻碍它的自由。本机方法可能可以访问虚拟机的运行时数据区域(这取决于本机方法接口),但也可以执行它想做的任何其他操作。

垃圾收集

JVM 管理 Java 中对象的整个生命周期。一旦创建了对象,开发人员就无需再担心它了。如果对象死亡(即不再有对它的引用),G​​C 会使用多种算法之一(串行 GC、CMS、G1 等)将其从堆中弹出。

在GC过程中,对象在内存中移动。因此,在该过程正在进行时,这些对象不可用。在此过程期间必须停止整个应用程序。这种暂停被称为“停止世界”暂停,并且是一个巨大的开销。GC 算法的主要目的是减少这个时间。我们将在接下来的章节中详细讨论这一点。

由于 GC,内存泄漏在 Java 中非常罕见,但也有可能发生。我们将在后面的章节中看到如何在 Java 中创建内存泄漏。