JVM 垃圾回收详解
在 Java 编程中,理解 JVM(Java Virtual Machine)的垃圾回收机制黑白常紧张的。垃圾回收是 JVM 自动管理内存的关键部分,它确保了步伐在运行过程中不会由于内存走漏而崩溃,同时也进步了开发服从,让开发者无需手动管理内存。本文将详细先容 JVM 垃圾回收机制。
一、JVM 内存结构概述
在深入了解垃圾回收之前,我们先来了解一下 JVM 的内存结构。JVM 内存重要分为以下几个区域:
[*]方法区(Method Area):存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。在 Java 8 及之前版本,方法区也被称为永久代(PermGen);从 Java 8 开始,使用元空间(Metaspace)来替代永久代,元空间使用当地内存,不再受限于 JVM 内存巨细。
[*]堆(Heap):这是 JVM 管理的最大一块内存区域,用于存储对象实例和数组等。几乎所有的对象实例都在这里分配内存。堆又分为新生代(Young Generation)和老年代(Old Generation)。
[*]新生代:通常用来存放新创建的对象。新生代又分为 Eden 区、Survivor From 区和 Survivor To 区。新创建的对象首先在 Eden 区分配内存,当 Eden 区满了之后,会触发一次 Minor GC(Young GC),将存活的对象复制到 Survivor From 区,然后清空 Eden 区。颠末多次 Minor GC 后,仍旧存活的对象会被晋升到老年代。
[*]老年代:存放颠末多次 Minor GC 后仍旧存活的对象。当老年代满了之后,会触发 Major GC(Full GC)。
[*]步伐计数器(Program Counter Register):当前线程所实行的字节码的行号指示器。每个线程都有一个独立的步伐计数器,它是线程私有的。
[*]虚拟机栈(Java Virtual Machine Stacks):每个方法在实行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。虚拟机栈也是线程私有的。
[*]当地方法栈(Native Method Stacks):与虚拟机栈雷同,但是它用于实行当地方法(Native Method)。
二、垃圾回收算法
JVM 中重要有以下几种垃圾回收算法:
[*] 标记 - 清除算法(Mark and Sweep)
[*]原理:首先标记出所有需要回收的对象,然后在标记完成后统一回收所有被标记的对象。
[*]优点:算法简单,容易理解。
[*]缺点:会产生大量的不连续的内存碎片,可能会导致以后在分配较大对象时无法找到足够的连续内存空间。
[*] 复制算法(Copying)
[*]原理:将内存分为巨细相称的两块,每次只使用此中一块。当这一块内存用完了,就将还存活的对象复制到另一块内存上,然后再把已使用过的内存空间一次整理掉。
[*]优点:实现简单,运行高效,不会产生内存碎片。
[*]缺点:将内存缩小为原来的一半,浪费了一半的内存空间。
[*] 标记 - 整理算法(Mark and Compact)
[*]原理:首先标记出所有需要回收的对象,然后让所有存活的对象都向一端移动,末了直接整理掉端界限以外的内存。
[*]优点:不会产生内存碎片。
[*]缺点:移动存活对象的操作比力耗时,服从相对较低。
[*] 分代收集算法(Generational Collection)
[*]原理:根据对象的存活周期将内存分别为新生代和老年代,针对差别代的特点采用差别的垃圾回收算法。
[*]新生代通常采用复制算法,由于新生代中的对象大多生命周期较短,复制算法可以高效地回收内存,并且不会产生内存碎片。
[*]老年代中的对象通常存活时间较长,采用标记 - 清除算法或标记 - 整理算法。
三、垃圾回收器
JVM 中有多种差别的垃圾回收器,下面先容几种常见的垃圾回收器:
[*] Serial 收集器
[*]特点:单线程收集器,在举行垃圾回收时,必须停息其他所有的工作线程,直到它收集结束。
[*]应用场景:适用于客户端应用等对停顿时间要求不高的场景。
[*] ParNew 收集器
[*]特点:是 Serial 收集器的多线程版本,除了使用多线程举行垃圾收集外,其他行为和 Serial 收集器完全一样。
[*]应用场景:与 CMS 收集器共同使用,在 Server 模式下的虚拟机中首选的新生代收集器。
[*] Parallel Scavenge 收集器
[*]特点:采用复制算法,是一个关注吞吐量的收集器。吞吐量 = 用户代码运行时间 / (用户代码运行时间 + 垃圾收集时间)。可以通过参数来调整垃圾收集的时间和频率,以到达更高的吞吐量。
[*]应用场景:适用于在后台运算而不需要太多交互的任务。
[*] Serial Old 收集器
[*]特点:Serial 收集器的老年代版本,单线程收集器,采用标记 - 整理算法。
[*]应用场景:在 Client 模式下与 Parallel Scavenge 收集器搭配使用;在 Server 模式下,作为 CMS 收集器发生失败时的后备预案。
[*] Parallel Old 收集器
[*]特点:Parallel Scavenge 收集器的老年代版本,多线程收集器,采用标记 - 整理算法。
[*]应用场景:注重吞吐量以及 CPU 资源敏感的场合。
[*] CMS(Concurrent Mark Sweep)收集器
[*]特点:以获取最短回收停顿时间为目的的收集器。采用标记 - 清除算法,整个过程分为四个阶段:初始标记、并发标记、重新标记、并发清除。初始标记和重新标记阶段需要停息所有的工作线程,但是这两个阶段的时间非常短;并发标记和并发清除阶段可以与用户线程一起工作,所以总体上看,CMS 收集器的停顿时间非常短。
[*]缺点:
[*]对 CPU 资源敏感:在并发阶段,固然不会导致用户线程停顿,但是会占用一部分 CPU 资源,导致应用步伐变慢。
[*]无法处置惩罚浮动垃圾:在并发标记和并发清除阶段,由于用户线程还在继续运行,所以会产生新的垃圾,这些垃圾称为浮动垃圾。CMS 收集器无法在当次收集中处置惩罚这些浮动垃圾,只能比及下一次垃圾回收时再举行处置惩罚。
[*]会产生内存碎片:由于采用标记 - 清除算法,会产生大量的内存碎片,可能会导致在分配大对象时无法找到足够的连续内存空间。
[*] G1(Garbage-First)收集器
[*]特点:面向服务端应用的垃圾收集器,重要目的是在满足短停顿时间的同时到达高吞吐量。G1 收集器将堆内存分别为多个巨细相称的 Region,每个 Region 可以是新生代也可以是老年代。它可以根据差别的 Region 的垃圾堆积情况,优先回收垃圾最多的 Region,从而实现高效的垃圾回收。
[*]过程:G1 收集器的垃圾回收过程重要包括以下几个阶段:初始标记、并发标记、最终标记、筛选回收。初始标记阶段和 CMS 收集器的初始标记阶段雷同,需要停息所有的工作线程,但是时间非常短;并发标记阶段和 CMS 收集器的并发标记阶段雷同,可以与用户线程一起工作;最终标记阶段需要停息所有的工作线程,但是时间也非常短;筛选回收阶段会根据用户设定的停顿时间,选择垃圾最多的 Region 举行回收,在回收过程中也会尽量减少停顿时间。
[*]优点:
[*]可预测的停顿时间:G1 收集器可以在不牺牲吞吐量的条件下,尽可能地减少停顿时间,并且可以通过参数设置来指定停顿时间的目的。
[*]并行与并发:G1 收集器在回收垃圾时,可以充分使用多 CPU、多核环境下的硬件上风,使用多个线程来举行垃圾回收,从而进步垃圾回收的服从。同时,在部分阶段可以与用户线程并发实行,进一步减少停顿时间。
[*]分代收集:G1 收集器依然采用分代收集的头脑,但是它将整个堆内存分别为多个 Region,每个 Region 可以根据需要扮演新生代大概老年代的脚色,如允许以更加灵活地举行垃圾回收。
四、如何优化垃圾回收
[*]公道设置堆内存巨细:通过调整 -Xms(初始堆巨细)和 -Xmx(最大堆巨细)参数,可以避免堆内存过小导致频仍的垃圾回收,大概堆内存过大导致长时间的垃圾回收停顿。一般来说,可以根据应用的实际需求和服务器的硬件资源来公道设置堆内存巨细。
[*]选择合适的垃圾回收器:差别的应用场景得当差别的垃圾回收器。例如,如果对停顿时间要求非常高,可以选择 CMS 或 G1 收集器;如果注重吞吐量,可以选择 Parallel Scavenge 和 Parallel Old 收集器。
[*]避免创建过多的短期对象:如果应用中创建了大量的短期对象,会导致新生代频仍举行垃圾回收,从而影响性能。可以通过对象复用、缓存等方式来减少短期对象的创建。
[*]监控和分析垃圾回收:可以使用 JVM 提供的工具(如 jstat、jvisualvm 等)来监控垃圾回收的情况,包括垃圾回收的频率、停顿时间、内存使用情况等。通过分析这些数据,可以实时发现问题并举行优化。
五、总结
JVM 的垃圾回收机制是一个复杂而紧张的系统,它自动管理内存,为 Java 步伐的稳定运行提供了保障。理解垃圾回收的原理、算法和收集器,以及如何优化垃圾回收,对于开发高效、稳定的 Java 应用步伐至关紧张。通过公道地设置 JVM 参数、选择合适的垃圾回收器以及优化代码,可以有效地进步应用步伐的性能和稳定性。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]