(1)GC调优1
通过官网查看查看JVM的参数:
可以使用java命令查看当前环境下的虚拟机参数:
学会使用一些工具如前面学的jmap ,jconsole等等工具
(2)GC调优2
垃圾回收调优只是众多调优中的一个方向,想要你的应用程序有更多的提升,要从各个领域进行分析进行调优,不光是GC这块,只是GC这块影响比较明显,可能影响你的网络延迟,因为一旦发生了Stop the World你的应用程序响应时间就会变长 ,下面的也是一种调优的方向:
对垃圾回收这块确定的调优 目标:需要确定自己的应用程序是用来干什么的,到底是做一些科学运算,还是做互联网项目,如果是科学运算追求的是高吞吐量,延长一点响应时间不是紧要的,这种情况下,就要追求一种高吞吐量的垃圾回收器,如果做的是互联网项目,那么响应时间呢,就是一个非常重要的指标了,因为每次的垃圾回收呢延长了你的响应时间,那么就会给用户造成不好的体验 。确定目标后选择合适的垃圾回收器
高吞吐量的垃圾回收器没有太多的选择只有一个ParallelGC
如果是低延迟响应时间优先可以选择CMS、G1、ZGC
jdk9中使用的是G1,它比CMS更好,相当于集成了CMS和ParallelGC之长特别适合管理超大的堆内存,可以做到低延迟,也可以想ParallelGC的吞吐量,确定是以吞吐量为目标或者响应时间为目标
ZGC是jdk12提出的一个体验的垃圾回收
还有一种叫做Zing的垃圾回收器,它对外宣称是0停顿,几乎没有Stop the World的时间,可以管理超大的内存
(3)GC调优3
在学jdbc的时候一下子查询出所有表的数据,把大量的数据加载到堆内存里 ,这样的堆内存在大,也经受不了多个这样的sql语句把大量的数据加载到堆内存里,像这种应该加一个limit限制一下返回的记录总数
另外一点数据是否臃肿:加载了一些不必要的数据比如说查询用户,来一个表连接把用户的信息全部查询出来,比如用户得详情,用户订单等等,数据查询出来以后不一定都用得上,在一次响应里只用到了一部分数据而不是所有,很多不是要什么查什么,而是一次性的把数据都查询出来,就可能造成内存得浪费
对象的大小:包装类比基本类型占用的大,这样呢可以从一方面来减少GC的压力,这样的对象呢极少成多,能节约的内存是相当可观的
存在内存泄露:错误的做法是定义了一个静态的Map变量,然后不断的想map中存放对象,这样呢就会造成内存可能溢出,最后可能发生GC,甚至内存溢出
像这种长时间存活的对象建议用可以使用软弱引用,软弱引用在内存吃力时做一下回收
像这种类似缓存的数据不建议使用java中的实现,因为毕竟不是专业做缓存的,可以使用第三方的缓存实现像Redis,他们都会考虑对象的过期,第三方的缓存实现不会造成对java堆的压力,
(4)GC调优_新生代1
当new一个对象时首先会在伊甸园中分配买这个分配速度是非常非常快的,每个线程呢都会在伊甸园中分配一个私有的区域,叫做TLAB这个区域,当new一个对象时首先在TLAB中看有没有个内存可以分配,有的话在这个区域呢做一个分配,因为我们对象的分配也有一个线程安全的问题比如说线程1用这个内存,在分配还没有结束时线程2也要这个内存,机会造成问题,因此需要做一个线程的并发安全保护,能不能减少线程对内存分配的一个冲突呢?TLAB线程局部缓冲区,它可以让每个线程用自己私有这块伊甸园内存做对象的分配,这样呢即是多个线程创建对象时也不会造成对内存的一个干扰
死亡对象的回收代价为0,我们知道新生代垃圾回收采用的是复制算法,复制算法的特点是我要把伊甸园,幸存区From中的幸存对象复制到幸存区To中去,复制完之后呢伊甸园的的内存都释放出来了因此呢死亡对象回收代价0
新生代的幸存对象很少又采用复制算法导致Minar时间很短
(5)GC调优_新生代2
怎么做新生代的垃圾调优呢?不就是把新生代调大一些嘛?但是调大情况下会出现一些问题:
太小容易触发Minar GC 太大了老年代不足容易触发Full GC时间更长
(6)GC调优_新生代3
尽可能的调大新生代:我们知道复制做占用的时间也是较多,因为涉及到占用内存块的移动,更新其他引用块的地址这个更耗时一些,但是因为新生代只有 少量的对象存活,那么复制时间也相对较 短,而标记时间较复制时间显得不是那么重要了,新生代调大主要的耗费还是在复制上,那么新生代真的很大也不会有明显的下降
一般设置下面的大小:一次响应产生的对象*并发量
(7)GC调优_新生代_幸存区
幸存区的对象:下面两种
当前存活的对象:声明周期较短,下一次垃圾回收就被回收掉了,但是现在还在使用它不能回收 ,暂时不能回收
需要晋升的对象:将来可能被晋升的对象,大家都在引用它,但是它的寿命还不够没有达到阈值,暂时存在幸存区
打下需要融那这两类对象。
幸存区如果很小那么jvm会动态调整晋升的阈值 ,也许有些对象寿命还不够轮不到它晋升,但是由于幸存区的内存太少,那么我们会提前把幸存区的对象晋升到老年代中去 ,比如这个存活时间较短的对象,晋升了那么就以为这只有等到老年代空间不足时才能回收,变相的延长了对象的存活时间
我们希望幸存时间短的对象留在幸存区里面,下次垃圾回收把它回收掉,
另一方面老长时间存活的对象,应该被尽快被提升,可以设置晋升阈值