3年前 (2021-09-17)  Java系列 |   抢沙发  293 
文章评分 0 次,平均分 0.0
[收起] 文章目录

垃圾收集:有很多技术定义,但用外行术语来说,它只是从内存中收集未引用或未使用(垃圾)对象并有效利用应用程序可用内存的一种自动化方法。

从这里开始,让我们节省一些空间,并使用“GC”作为垃圾收集的缩写。

GC的发展

在java之前,用C或C++,我们必须使用MalCube()/RealCube()/CalOrthAube(/For)/free()来显式分配或分配内存。因为我们必须显式地管理内存分配,任何错误都会使应用程序容易出现内存泄漏。随着Java的出现,自动GC的概念被引入。

  • 吞吐量:运行应用程序时花费的平均时间与GC中花费的平均时间
  • 延迟:GC期间代码暂停的时间量
  • :内存中存储java对象的区域。
  • 年轻代:堆中存储新创建对象的区域。
  • 老年代(永久):堆中存储长寿命对象的区域。

Minor GC:java中的大多数对象都是短期的。这意味着他们是被创造出来的,他们早死。因此,年轻一代中的大多数对象都是通过较小的GC收集的。之所以称之为Minor,是因为它在应用程序上成本较低,并且不会增加额外的暂停或延迟。

Major GC:在次要GC之后存活下来的对象从年轻一代移动到老一代空间,一旦老一代空间达到其阈值,就会触发主要GC,在大多数情况下,这是停止世界(STW)操作,并通过暂停所有线程增加应用程序的开销,从而导致延迟。因此,了解不同类型的GC并为我们的应用程序选择正确的GC是非常重要的。

所以,这些基本术语和定义已经做得够多了。我们是来了解超高速垃圾收集器的,不是吗??但是等一下!!!如果我们不知道现有GC机制的速度有多快,我们如何量化超快。让我们再花几分钟讨论一下现有的GC机制。

现有的GC

GC分为两个简单步骤:标记和扫描。标记标记符合垃圾收集条件的对象。扫掠将删除由“标记”步骤标记的对象。

Serial GC 串行GC

使用单个应用程序线程执行GC并冻结所有应用程序线程(STW),这使得它不太适合低延迟应用程序和多线程应用程序。

java -XX:+UseSerialGC -jar Application.java

能够提供一些应用程序暂停时间的应用程序可以使用以下参数启用此GC。主要用于单线程应用程序。

Parallel GC 并行GC

这是JVM的默认GC,与串行GC不同,它使用多个线程来执行GC,因此它比串行GC快,但在运行时再次冻结其他应用程序线程(STW)。这可以通过以下方式启用:

java -XX:+UseParallelGC -jar Application.java

适用于多线程应用。

然而,如果我们想使用这个GC,我们可以使用不同的选项来最小化STW的影响。

-XX:ParallelGCThreads:用于GC的并行线程

-XX:MaxGCPauseMillis:GC期间的最大暂停时间。为了满足此SLA,GC可以对其他参数进行一些调整。

-XX:GCTimeRatio:所需的最大吞吐量。

CMS(并行标记和扫描)

这将使用多个垃圾收集器线程进行垃圾收集。它是为那些希望垃圾收集暂停时间更短的应用程序而设计的。如果超过98%的总时间花费在CMS垃圾收集中,并且只有不到2%的堆被恢复,那么CMS收集器将抛出OutOfMemoryError。如有必要,可通过在命令行中添加选项-XX:-usegcoveredlimit来禁用此功能。CMS可以使用

java -XX:+UseConcMarkSweepGC -jar Application.java

与串行和并行GC相比,暂停时间更短

CMS在Java9之后被弃用,如果我们使用它,它会抛出一个警告。在Java14中,它被完全删除。

G1 GC

G1代表垃圾优先。与其他收集器不同,G1收集器从JDK7开始提供,它将堆划分为一组大小相等的堆区域,每个区域都有一个连续的虚拟内存范围。在标记阶段,G1显示了一个并发的全局标记阶段,以确定整个堆中对象的活跃度。在扫描过程中,G1知道哪些区域大部分是空的。它首先聚集在这些区域,这通常会产生大量的自由空间。这就是为什么这种垃圾收集方法被称为垃圾优先。

G1是为运行在具有大内存空间的多处理器机器上的应用程序而设计的。它的性能效率更高。它可以通过以下方式启用:

java -XX:+UseG1GC -jar Application.java

高堆应用程序的低GC暂停时间

超快速GC

到目前为止,所有的JDK GC都在阻止世界上存在应用程序延迟问题的操作。在最新版本的Java(>JDK11)中,引入了两个新的GC,ShenandoahZGC。这些GC允许java应用程序在并发收集垃圾的同时运行。让我们看看。

Shenandoah

在JDK12中引入的Shenandoah对G1的关键改进是与应用程序线程同时执行更多的垃圾收集周期工作。G1只有在应用程序暂停时才能清空堆区域,即移动对象,而Shenandoah可以与应用程序同时重新定位对象。为了实现并发重新定位,它使用了一个被称为Brooks指针的东西。这个指针是Shenandoah堆中每个对象都拥有的附加字段,它指向对象本身。

Shenandoah这样做是因为当它移动一个对象时,它还需要修复堆中所有引用该对象的对象。当Shenandoah将对象移动到新位置时,它会保留旧的Brooks指针,将引用转发到对象的新位置。当引用对象时,应用程序将遵循指向新位置的转发指针。最终需要清理带有转发指针的旧对象,但通过将清理操作与移动对象本身的步骤分离,Shenandoah可以更轻松地完成对象的并发重新定位。

GC暂停时间与不同的堆大小一致,即200 MB堆的暂停时间与200 GB堆的暂停时间相同。是的,你读对了!!

要在Java 12以后的应用程序中使用Shenandoah,请使用以下选项启用它:

java -jar -XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC Application.java

如果您还没有迁移到JDK 12,Shenandoah支持到JDK 8和JDK 12的后端端口。此外,在Oracle提供的JDK版本中没有启用Shenandoah,但是其他OpenJDK发行商默认启用Shenandoah

当需要低延迟并且应用程序迁移到OpenJDK时,请使用Shenandoah

ZGC

ZGC是Java11中的一个实验特性,它具有低延迟和可扩展的垃圾收集器。ZGC的一致GC暂停时间为2ms,保证的最大GC暂停时间为10ms,这使得它的速度非常快,可以处理TB大小的堆。

ZGC暂停时间不随堆大小的增加而增加。ZGC允许Java应用程序在执行除线程堆栈扫描之外的所有垃圾收集操作时继续运行。它还支持并发类卸载。执行并发类卸载是复杂的,因此,类卸载传统上是在停止世界暂停时完成的。确定不再使用的类集需要首先执行引用处理。引用处理成本很高,在最坏的情况下需要扫描整个堆。嗯,ZGC同时执行所有这些操作,因此在类卸载期间不会对延迟进行惩罚。ZGC可通过以下方式启用:

java -XX:+UnlockExperimentalVMOptions -XX:+UseZGC -jar Application.java

ZGC中的“Z”是什么?没什么,只是个“Z”!!

以下是SPECJbb发表的一些比较研究

Java中的超高速垃圾收集器 Java中的超高速垃圾收集器

 

ZGC非常适合需要大量内存的应用程序,例如大数据。但是,对于需要可预测且极低暂停时间的较小堆,ZGC也是一个很好的选择。

总结

这就是新的超高速垃圾收集器。它们的速度非常快,因为它们在不暂停应用程序线程的情况下同时执行所有标记和扫描。根据应用程序需要选择垃圾收集器。别忘了用不同的GC机制对应用程序的性能进行基准测试,看到一个JVM交换机可以产生的影响,您会大吃一惊。

 

除特别注明外,本站所有文章均为老K的Java博客原创,转载请注明出处来自https://javakk.com/2349.html

关于

发表评论

表情 格式

暂无评论

登录

忘记密码 ?

切换登录

注册