Java虚拟机&垃圾回收

垃圾回收

垃圾收集是通过销毁未使用的对象,回收运行时未使用的内存的过程。垃圾收集器利用垃圾收集根(GCRoots)的概念来识别活动对象和死亡对象。

  • 有系统类加载器加载的类(不是自定义类加载器)
  • 实时线程
  • 当前执行方法的局部变量和参数
  • JNI方法的局部变量和参数
  • 全局的JNI参考
  • 用作同步监视器的对象
  • JVM出于其目的而从垃圾回收中保留的对象

Java垃圾收集的各个阶段

  • 将对象标记为活动状态。 当 GC 访问一个对象时,它会将其标记为可访问并因此处于活动状态。垃圾收集器访问的每个对象都被标记为活动对象。所有无法从 GC Root 到达的对象都是垃圾,并被视为垃圾收集的候选对象。

  • 扫描死亡对象。 标记阶段之后,我们就有了由活(已访问)对象和死(未访问)对象占用的内存空间。清除阶段释放包含这些死对象的内存碎片。

  • 压缩内存剩余的对象。 在扫描阶段移除的死对象不一定彼此相邻。因此,您最终可能会拥有碎片化的内存空间。垃圾收集器删除死对象后可以压缩内存,以便剩余对象位于堆开头的连续块中。压缩过程使按顺序为新对象分配内存变得更容易。

Java分代垃圾收集

JVM中的堆内存区域分为三部分:

老年代

当幸存的对象在幸存者空间中移动达到一定阈值时,它们就会被移动到老年代。您可以使用该-Xmn标志来设置年轻代的大小。

为对象的任期定义了一个阈值,该阈值决定了在将其移至老一代之前可以存活多少个垃圾收集周期。当对象从老年代被垃圾回收时,它是一个主要的垃圾回收事件。您可以使用-Xms和-Xmx标志来设置堆内存的初始大小和最大大小。

总结一下:当一个对象被创建时,它首先被放入年轻代的Eden空间 中。一旦发生较小的垃圾回收,来自Eden 的活动对象就会被提升到FromSpace。当下一次次要垃圾回收发生时,Eden和FromSpace中的活动对象都会移动到ToSpace中。这个循环持续特定的次数。如果该对象在此之后仍然被使用,则下一个垃圾收集周期会将其移动到老年代空间。

永久代

类和方法等元数据存储在永久代中。它由 JVM 在运行时根据应用程序使用的类进行填充。您可以使用-XX:PermGen和-XX:MaxPermGen标志来设置永久代的初始大小和最大大小。

元空间

从 Java 8 开始,MetaSpace内存空间取代了PermGen空间。该实现与 `PermGen 不同,元空间的堆大小也会自动调整。

垃圾收集器的类型

  • 串行垃圾收集器的jvm参数是:-XX:+UseSerialGC。整个应用程序暂停。由于整个应用程序在垃圾收集期间被冻结,因此在需要低延迟的现实场景中不建议这样做。

  • 并行垃圾收集器的JVM 参数是-XX:+UseParallelGC。由于它更适合多线程环境,因此可以在需要完成大量工作并且可以接受长时间暂停的情况下使用它,例如运行批处理作业。

  • CMS(并发标记清除) GC 这也称为并发低暂停收集器的JVM 参数是-XX:+UseConcMarkSweepGC。多个线程用于次要垃圾回收,使用与并行相同的算法。主要垃圾收集是多线程的,就像并行旧 GC 一样,但 `CMS`` 与应用程序进程同时运行,以最大限度地减少停止事件。因此,CMS 收集器比其他 GC 使用更多的 CPU。如果您可以分配更多的CPU以获得更好的性能,那么CMS垃圾收集器是比并行收集器更好的选择。CMS GC 中不执行压缩。

  • G1(垃圾优先) G1 垃圾收集器的JVM参数是-XX:+UseG1GC。GC 专为具有较大可用堆大小(超过 4GB)的多线程应用程序而设计。它像 CMS 一样是并行和并发的,但与旧的垃圾收集器相比,它的工作原理完全不同。虽然G1也是分代的,但是它没有单独的年轻代和老年代的区域。相反,每一代都是一组区域,这允许以灵活的方式调整年轻代的大小。由于G1GC会识别出垃圾最多的区域,并首先对该区域进行垃圾收集,因此称为垃圾优先。

  • Epsilon 垃圾收集器的 JVM 参数是-XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC Epsilon 是一个不执行任何操作(no-op)的垃圾收集器,作为 JDK 11 的一部分发布。它处理内存分配,但不实现任何实际的内存回收机制。一旦可用的 Java 堆耗尽,JVM 将关闭。

  • Shenandoah 垃圾收集器的 JVM 参数是-XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC 它与应用程序线程同时执行更多垃圾收集周期工作。G1 仅在应用程序暂停时才能清空其堆区域,而 Shenandoah 可以与应用程序同时重新定位对象。Shenandoah 可以在检测到可用内存后立即压缩活动对象、清理垃圾并将 RAM 释放回操作系统。由于所有这些都是在应用程序运行时同时发生的,Shenandoah 的 CPU 密集度更高。

  • ZGC 是另一种 GC垃圾收集器的 JVM 参数是-XX:+UnlockExperimentalVMOptions -XX:+UseZGC,作为 JDK 11 的一部分发布,并在 JDK 12 中进行了改进。它适用于需要低延迟(少于 10 毫秒暂停)和/或使用非常大的堆(数 TB)的应用程序。ZGC 的主要目标是低延迟、可扩展性和易用性。为了实现这一点,ZGC 允许 Java 应用程序在执行所有垃圾收集操作时继续运行。默认情况下,ZGC取消提交未使用的内存并将其返回给操作系统。因此,ZGC 通过提供极低的暂停时间(通常在 2 毫秒内),比其他传统 GC 带来了显着改进。