JVM相关知识

Java中的JVM(Java Virtual Machine,Java虚拟机)是一个抽象的计算机,它提供了一个运行时环境来执行Java字节码。JVM的结构清晰且复杂,主要包括以下几个关键组件:

1. 类加载器(Class Loader)

功能:负责将Java类文件加载到内存中,并生成对应的Class对象。它是Java实现动态性和灵活性的关键之一。

加载过程:包括加载(Loading)、链接(Linking,分为验证、准备和解析三个阶段)和初始化(Initialization)三个阶段。

2. 运行时数据区域(Runtime Data Area)

这是JVM在执行Java程序时用于存储各种数据的内存区域,主要包括:
方法区(Method Area,在Java 8及以后被元空间取代):存储已被虚拟机加载的类的信息、常量、静态变量、即时编译器编译后的代码等数据,是线程共享的。

  • 字符串常量池:Java中用于存储字符串字面量的一个特殊区域,它位于方法区(在Java 8及之前的版本)或元空间(在Java 8及之后的版本)中。

本地方法栈 (Native Method Stack):为Java虚拟机使用到的Native方法服务,与Java虚拟机栈类似,但用于执行本地方法,也是线程私有的。
虚拟机栈(Java Virtual Machine Stacks):每个Java方法在执行时都会创建一个栈帧(Stack Frame),用于存储局部变量表、操作数栈、动态链接、方法出口等信息,是线程私有的。

  • 栈帧内部名词解释

  • 局部变量表(Local Variable Table)

    局部变量表用于存储方法的局部变量和参数。这些变量在方法执行期间有效,并在方法结束时被销毁。局部变量表的大小在编译期间就确定了,因此在方法调用时会分配足够的空间来存储这些变量。每个局部变量占用一个或多个变量槽(Variable Slot),具体取决于变量的数据类型。例如,int、float等32位以内的数据类型占用一个槽,而long、double等64位的数据类型占用两个槽。

  • 操作数栈(Operand Stack)

    操作数栈用于存放方法执行过程中的操作数和中间结果。它是一个后进先出(LIFO)的数据结构,用于支持方法的计算过程。在方法执行时,指令会从操作数栈中取出操作数,执行计算、赋值等操作,然后将结果再次存入操作数栈中。每个栈帧都有一个独立的操作数栈,多个栈帧之间不共享操作数栈。

  • 动态链接(Dynamic Linking)

    动态链接用于存储方法调用过程中的符号引用和直接引用的关系。在Java中,方法的调用是通过符号引用来表示的,这些符号引用在类加载期间被解析为直接引用。动态链接就是在运行时将这些符号引用转换为直接引用的过程。它支持方法的动态调用和多态性。

  • 方法返回地址(Return Address)

    方法返回地址用于存储方法执行完成后需要返回到的调用者的地址。当方法执行完毕后,JVM会根据这个地址将控制权返回给调用者。这是实现方法调用的重要机制之一。

  • 附加信息(Additional Information)

    除了上述主要组成部分外,栈帧还可能包含一些附加信息,如方法调用者的信息、方法的访问权限、异常处理表等。这些信息用于支持方法的执行和异常处理。

Java堆(Java Heap):存储Java对象实例和数组,是Java程序运行时的动态内存区域,也是垃圾收集器管理的主要区域。堆通常分为新生代、老年代和永久代(在Java 8及以后被元空间取代)。

  • 运行时常量池(Runtime Constant Pool):每个类或接口在编译时生成一个对应的常量池表,在运行时被加载到方法区的运行时常量池中。在Java 8及以后,运行时常量池被移到了堆中。

程序计数器 (Program Counter Register):存储当前线程执行的字节码指令地址,是线程私有的。
直接内存(Direct Memory):通过NIO库可以直接使用的内存,不受Java堆的限制,也不受垃圾回收的管理。

3. 执行引擎(Execution Engine)

功能:负责执行字节码,包括解释器和即时编译器(JIT)等。解释器逐条解释执行字节码,而JIT则可以将热点代码编译成机器码以提高执行效率。

4. 垃圾回收器(Garbage Collector, GC)

功能:自动管理内存,回收不再使用的对象,释放内存空间。JVM提供了多种垃圾回收算法和回收器,如标记-清除、复制、标记-整理以及分代收集等,以适应不同的应用场景和需求。

Minor GC默认处理机制

Minor GC主要处理新生代(Young Generation)中的垃圾回收。新生代通常包括Eden区和两个Survivor区(Survivor From和Survivor To)。以下是Minor GC默认的处理机制:

  • 标记复制算法:
    Minor GC通常使用标记复制算法。该算法首先标记出新生代中存活的对象,然后将这些对象复制到一个空闲的Survivor区或老年代中。
    复制过程完成后,原来的Eden区和Survivor区中的对象将被清空,用于下一次对象的分配。
    垃圾回收器选择:
    不同的JVM实现和版本可能选择不同的垃圾回收器作为Minor GC的默认实现。
    例如,在Java 8之前的HotSpot JVM中,Serial和Parallel垃圾回收器是常用的Minor GC实现。
    在Java 8及之后的版本中,G1(Garbage-First)垃圾回收器成为了一种流行的选择,因为它提供了更好的性能和可预测性。

Full GC默认处理机制

Full GC处理整个堆内存(包括新生代和老年代)以及方法区(在Java 8之前为永久代PermGen,之后为元空间Metaspace)中的垃圾回收。以下是Full GC默认的处理机制:

  • 标记清除或标记整理算法:
    Full GC通常使用标记清除或标记整理算法。标记清除算法首先标记出堆内存中的存活对象,然后清除未标记的对象。
    标记整理算法在标记存活对象后,还会对存活对象进行整理,以消除内存碎片。
    需要注意的是,不同的垃圾回收器可能会选择不同的算法。例如,CMS(Concurrent Mark-Sweep)垃圾回收器使用标记清除算法,而G1垃圾回收器则使用标记整理算法。
    垃圾回收器选择:
    与Minor GC类似,Full GC的默认实现也取决于JVM的具体实现和版本。
    在Java 8之前的HotSpot JVM中,CMS垃圾回收器是一种流行的Full GC实现,因为它旨在减少停顿时间。
    在Java 8及之后的版本中,G1垃圾回收器成为了默认的Full GC实现,因为它提供了更好的性能和可预测性。
    触发条件:
    Full GC的触发条件包括老年代空间不足、方法区空间不足、显式调用System.gc()方法(尽管这只是一个建议,JVM不一定会立即执行Full GC)等。
    当触发Full GC时,JVM会暂停所有应用程序线程(Stop-the-World),以对整个堆内存进行垃圾回收。

5. Java中常见垃圾收集器的执行过程

  • Serial收集器

    Serial收集器是一个单线程的垃圾收集器,它在进行垃圾收集时,会暂停所有的应用线程(Stop-The-World,简称STW),直到垃圾收集工作完成。这个过程主要分为以下几个阶段:
    标记阶段:从GC Roots出发,标记所有可达的对象。
    清除阶段:遍历堆内存,清除所有未标记的对象。

    由于Serial收集器是单线程的,因此它的垃圾收集效率相对较低,适用于内存较小、对性能要求不高的应用。

  • Parallel收集器

    Parallel收集器是一个多线程的垃圾收集器,它使用多个线程并行地进行垃圾收集,以提高垃圾收集的效率。Parallel收集器的执行过程与Serial收集器类似,但它是多线程并行的。
    年轻代收集:使用并行复制算法,将存活的对象从一个Survivor区复制到另一个Survivor区或老年代。
    老年代收集:使用并行标记-压缩算法,标记所有可达的对象,并压缩堆内存中的空闲空间。

    Parallel收集器适用于多线程、对吞吐量有较高要求的应用。

  • CMS(Concurrent Mark Sweep)收集器

    CMS收集器是一个以最小化停顿时间为目标的垃圾收集器。它采用并发标记和并发清除的方式进行垃圾回收,以减少应用程序的停顿时间。

    CMS收集器的执行过程如下:
    初始标记阶段:STW,标记GC Roots直接可达的对象。 并发标记阶段:与应用线程并发执行,标记所有可达的对象。
    重新标记阶段:STW,处理并发标记阶段产生的所有新引用,并标记这些新引用的对象。 并发清除阶段:与应用线程并发执行,清除所有未标记的对象。

    CMS收集器的优点在于能够显著降低应用程序的停顿时间,但缺点是可能会占用较多的CPU资源,并且可能会产生内存碎片。

  • G1(Garbage-First)收集器

    G1收集器是一个面向大内存、需要低停顿时间的应用的垃圾收集器。它将堆内存划分为多个大小相等的区域(Region),并优先处理垃圾最多的区域。G1收集器的执行过程如下:
    并发标记阶段:与应用线程并发执行,标记所有可达的对象,并计算每个区域的垃圾比例。
    混合回收阶段:根据设置的停顿时间和垃圾比例,选择部分年轻代区域和部分老年代区域进行回收。回收时,将存活的对象复制到其他区域,并更新指向已回收区域的对象引用。
    并发整理阶段:在必要时,对老年代进行并发整理,以减少内存碎片。

    G1收集器的优点在于能够动态调整堆内存的使用,降低停顿时间,并提供可预测的垃圾回收性能。但缺点是配置和调优相对复杂。

  • ZGC和Shenandoah收集器

    ZGC和Shenandoah收集器是Java后续版本中引入的低延迟垃圾收集器。它们采用了一些先进的技术,如染色指针、内存多重映射等,以实现极低的停顿时间。
    ZGC收集器

    ZGC收集器基于Region内存布局,不设分代,使用读屏障、染色指针和内存多重映射等技术来实现标记-整理算法。它的停顿时间可以控制在几毫秒以内。
    Shenandoah收集器
    (注意:在某些版本的JVM中可能已经被移除或替换为其他收集器)

    Shenandoah收集器也采用了类似的并发标记和整理技术,旨在提供低延迟的垃圾回收性能。

相关推荐
HUNAG-DA-PAO3 小时前
Spring AOP是什么
java·jvm·spring
No regret.4 小时前
JVM内存模型、垃圾回收机制及简单调优方式
java·开发语言·jvm
东阳马生架构13 小时前
JVM实战—2.JVM内存设置与对象分配流转
jvm
撸码到无法自拔14 小时前
深入理解.NET内存回收机制
jvm·.net
吴冰_hogan1 天前
JVM(Java虚拟机)的组成部分详解
java·开发语言·jvm
东阳马生架构2 天前
JVM实战—1.Java代码的运行原理
jvm
ThisIsClark2 天前
【后端面试总结】深入解析进程和线程的区别
java·jvm·面试
王佑辉2 天前
【jvm】内存泄漏与内存溢出的区别
jvm
大G哥2 天前
深入理解.NET内存回收机制
jvm·.net
泰勒今天不想展开2 天前
jvm接入prometheus监控
jvm·windows·prometheus