hotspot虚拟机垃圾收集调优指南(jdk14)

       java作为一门比较有历史的语言,从他发明出来开始就有了GC功能,GC作为jvm非常重要的一个功能模块,不同厂商都有自己的实现,本文以hotspot jdk14为例,参考hotspot虚拟机调优白皮书,从宏观角度介绍GC机制,希望通过阅读本文能对hotspot GC有一个大体的认识,在对GC调优的时候能有一个基本的思路

1.GC的介绍

       我们在谈GC的时候,我觉得有必要先给GC一个清楚的定义,一个完整的GC器,他需要做到以下几件事情

1.从操作系统申请或者返回内存
2.当应用程序申请内存时分配给他内存
3.确定哪些内存仍然被应用程序使用
4.回收无用的内存以便应用程序重复使用

    GC在完成这些工作的时候,hotspot虚拟机会运用不同的技术去提高它的工作效率比如采用分代回收的策略能够让大部分无用的对象集中在一起集中回收、采用多线程后台并行的方式回收以及压缩活动对象获得连续可用空间。

    hotspot虚拟机提供了多种不同的垃圾收集器,其实在大部分情况下,系统默认的收集器都能很好的工作,并不需要我们去选择其中某一个,但是在一些比如数据量比较大多线程和高事务处理频率,这种情况下就不一样了,从某种角度来分hotspot虚拟机垃圾收集器可以分为serial GC和非serial GC,一个是单线程一个是多线程,下图展示了在小型系统可忽略的吞吐量的问题在大型系统中可能是一个大的瓶颈

 

    在减少瓶颈方面进行一些小的改进可以提高性能,对于大型系统,有必要选择正确的垃圾收集器并在必要时进行一些调整
串行收集适合一些小的系统,非串行的垃圾收集器设计复杂有额外的开销,但是在一些大型应用程序线程密集型,串行收集就不合适了,默认情况下使用G1垃圾收集器

2.基于行为调优 (吞吐量 VS 最大停顿时间)

     我们的系统应用场景的不同,就有不同的侧重点,比如晚上跑的大数据任务它可能更希望有更高的吞吐量使得更多的时间在执行应用程序,但是一些和用户交互的程序对停顿时间就相当敏感,所以我们要针对不同的情况找到不同的侧重点来进行系统的优化,我们可以通过-verbose:gc命令设置打印gc信息

    可以将hotspot垃圾收集器配置为优先满足以下两个目标之一:最大停顿时间或者吞吐量。如果达到了首选目标,GC将尝试将另一个目标最大化。当然,这些目标并不是总能够满足的:应用程序需要足够最小的堆来容纳所有实时数据,而且一些其他的配置可能会影响达到其他的目标。

   吞吐量

       吞吐量目标可以通过-XX:GCTimeRatio=nnn进行设置,GC时间和应用程序执行的时间之比为1 /(1+nnn)比如,-XX:GCTimeRatio=19这个意思就是GC收集时间为总时间的5%。GC所花费的时间是所有GC引起的暂停的总时间。如果没有达到吞吐量目标,那么垃圾收集器可能会增加堆的大小,以便在两次收集暂停之间能够花更多的时间在应用程序执行上面。

   最大停顿时间     

     最大停顿时间可以通过-XX:MaxGCPauseMillis=<nnn>进行设置,这个配置告诉虚拟机希望暂停时间为<nnn>毫秒或更少,垃圾收集器可能会调整Java堆大小和其他与垃圾收集相关的其他参数,以使垃圾收集的暂停时间短于<nnn>毫秒。最大暂停时间的默认值因收集器而异。更短的停顿时间可能导致GC更频繁的发生,从而降低了应用程序的整体吞吐量。而且,在有些情况下,设置的最大的停顿时间有时候也是达不到的,这很好理解,你不能给虚拟机设置一个它根本达不到的值。

    堆会增长或者收缩达到所选的吞吐量目标。一般来讲不要为堆设置一个最大值,除非你知道你的系统需要的堆大于默认的堆大小,选择一个吞吐量的目标一般就足够了,应用程序行为的改变可能导致堆增长或者收缩。比如,如果应用程序开始以更高速率分配内存,那么堆会增长以保持相同的吞吐量。如果堆达到了最大值,但是吞吐量的目标依然无法满足,那么堆的最大值对于吞吐量目标来说还是小了,将堆设置为接近平台物理总内存的值,注意不要产生Swapping,再次启动系统,如果吞吐量目标还是达不到,那么对于这个平台而言这个吞吐量目标设置的太大了,如果吞吐量目标可以满足,但是停顿时间太长,则选择最大停顿时间目标。选择最大停顿时间目标可能意味着吞吐量目标将无法实现,因此选择一个对于系统可接受的折衷值。

  如果已经满足吞吐量和最大停顿时间目标,则垃圾收集器会减小堆的大小,直到无法满足其中一个目标(始终是吞吐量目标)。可以通过: -Xms=<nnn> 和 -Xmx=<mmm> 分别用于最小和最大堆的设置。默认设置下初始堆大小为物理内存的64/1 默认最大堆大小为物理的内存的1/4

    3.分代回收

     hotspot虚拟机有不同的垃圾回收器,除了ZGC外,其他的垃圾回收器都使用了分代回收的技术,我们看下面这种图

 

     在启动时,hotspot虚拟机在地址空间中保留了整个Java堆,最大可用的堆空间可以通过-Xmx指定,当-Xms参数小于-Xmx,不是所有的内存空间都提交给虚拟机,未提交的在图上标记为virtual,年轻代和老年代可以根据需要增长到virtual的极限,整个堆的地址空间在逻辑上分为年轻代和年老代。年轻代由一个eden区和两个survivor区组成,其中有一个survivor区在任何时候都是空闲的,在年轻代垃圾收集的时候(年轻代GC也称为minor收集),把eden区和其中一个survivor区存活的对象拷贝到另一个survivor区,拷贝达到一定的次数,或者survivor区的空间不够了,对象就会拷贝到老年代,这也称为对象的老化,当老年代空间不够的时候会触发整堆回收(也称为major收集),major收集通常要比minor收集更耗时,因为很明显,它包括更多的对象。

    影响GC性能有两个重要点,一个是整个堆的大小,还有一个就是年轻代的大小,一般整堆的默认大小通常都会太小,我们应该给虚拟机足够的内存空间,还有如果-Xms ,-Xmx设置为一样的值,那么虚拟机会失去一些调节选择的能力,有时候这可能不是一个好的选择,默认情况下,虚拟机在GC的时候增加或缩小堆,以尽量将可用空间比例保持在特定范围内。通过-XX:MinHeapFreeRatio=<最小>(默认值为40%)和-XX:MaxHeapFreeRatio=<最大>(默认值为70%)设置一个空闲空间百分比,但是内存的占用不会超过-Xms ,-Xmx 的上下限,比如最低空闲比例是40%,当堆中空闲空间百分比低于40%时候堆会扩张以维持40%的空闲空间。相应的,如果空闲空间超过70%,那么堆会收缩。谈了整堆的大小,另一个重要的点就是年轻代堆,通过-XX:NewRatio可以设置年轻代堆的大小,比如-XX:NewRatio=3(默认是2)意味着年轻代(eden区加两个survivor区)和老年代比例是1:3,选项-XX:NewSize和-XX:MaxNewSize和-Xms ,-Xmx一样更精确的限制年轻代堆大小的上下限,比-XX:NewRatio比例设置有更小的粒度,用-XX:SurvivorRatio可以去设置survivor区的大小,-XX:SurvivorRatio=6(默认是8)意味着一个survivor区和eden区的比例是1/6,因为有两个survivor区,那么一个survivor区占总个年轻代的1/8,如果survivor区设置的太小,那么年轻代垃圾收集的时候更容易把对象复制到老年代,如果survivor区设置的太大,那么就会浪费许多无用的空间,虚拟机会有一个对象在老化之前可以被复制的次数的阈值,这个阈值是为了让survivor区保持一个半满的状态,

     对于你的服务来说,首先确定你的最大堆的大小,最大堆的大小应该受限于机器的物理内存,否则会有一些页面错误或者抖动,根据年轻代性能指标找到一个合适的值,在总堆大小是固定的情况下,增加年轻代内存就意味着老年代内存会减少,尽量给老年代给多的内存能够容得下实时的数据,再加上一些闲置空间(10到20%或更多),在前面的基础上,尽量给年轻代更多的内存,增加处理器的时候也给年轻代更多内存,因为内存分配可以并行

    4.几个可用的垃圾回收器

   Serial收集器

     Serial收集器使用单线程执行工作,这使得它比较高效,不需要处理多线程之间的交互,它非常适合单处理器,因为它也利用不了多处理器资源,在数据量较小的(大约100MB)多处理器上它也有用,可以通过-XX:+UseSerialGC显示的指定。

  Parallel收集器

    Parallel收集器也是吞吐量优先的收集器,它和Serial的区别在于一个是单线程,一个是多线程,Parallel收集器适用于中大数据集或者多核的应用程序。可以通过-XX:+UseParallelGC显示的指定

  Garbage-First (G1)收集器

    G1是一个并行的收集器。替代以前的CMS收集器,可以垃圾收集和应用程序并发的执行。G1设计用于从小型机器扩展到具有大量内存的大型多处理器机器,G1满足小的停顿时间同时兼顾大的吞吐量。G1是大多数服务器默认的选择,可以通过-XX:+UseG1GC显示的指定。

  ZGC收集器

    ZGC是一种可扩展低延迟的收集器,也是一个并行收集器,ZGC适用于需要低延迟(暂停时间小于10毫秒)和/或使用非常大的堆(tb级别)的应用程序。可以通过-XX:+UseZGC选项启用。从从JDK 11开始ZGC作为一个实验性质的垃圾收集器

  如何选择一个垃圾收集器

    除非应用程序有相当严格的暂停时间要求,否则使用vm默认的垃圾收集器,如果必要的话调整堆的大小来提升性能,如果还不行的话,有这么一些指导意见,1.如果应用程序数据量非常小(最多大约100 MB)或者在单处理器上运行并且也没有停顿时间要求,那么使用Serial收集器。2.如果应用程序性能是第一优先级,并且没有暂停时间要求或者1秒或更长时间的暂停是可以接受的,那么使用Parallel收集器。3.如果响应时间比吞吐量更重要,那么使用G1收集器,4.如果响应时间非常重要,并且正在使用一个非常大的堆,那么使用ZGC收集器。以上这些意见只是作为一个基本的准则,性能还是主要取决于堆的大小、应用程序活动数据量以及可用处理器的数量和速度。如果推荐的收集器没有达到预期的性能,那么首先尝试调整堆和分代大小以满足预期的目标。如果性能仍然不够,那么尝试不同的收集器(使用并行收集器减少暂停时间,Parallel收集器提高多处理器硬件上的总体吞吐量)。

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值