深刻了解JVM - 阶段总结与回顾(二)

前言

上一文为:深刻了解JVM - 阶段总结与回顾(一),阶段总结一次要内容为JVM的一些调优常识储备以及后面的文章回顾,这一节将会总结一些JVM常见的调优套路,帮忙大家在理论状况中遇到问题的时候不用慌乱,这里要特别强调一点:平时写代码要常常回顾和逻辑梳理,对于一些不确定的办法肯定要点开源码进行解读。

之前有评论说思维导图更直观一些,所以后续的文章都会尽量附上思维导图节俭大家的工夫。

前文回顾:

上一节咱们给了两个简略的案例,解说了FULL GC的常见排查套路,依据排查套路能够帮忙咱们疾速找到排查的方向并且及时的定位到真正的问题点,这对于排查线上问题是一项很重要的技能。

另外咱们还讲述了String.split()是如何让JVM频繁进行FULL GC的,咱们用图表一步步剖析出基本后果,并且解读源码剖析了这个办法在JDK版本升级的改变,因为降级后源代码在切割字符串之后创立SubList对象(底层为数组)导致这一问题的产生,这里JDK要背一部分锅,因为它违反了 向下兼容这一规定,然而更多状况下是因为开发人员对于办法理解水平不够,最终导致代码逻辑产生内存透露!

以上就是上一节的所有内容。

阶段总结:

在个人主页也有历史文章,欢送来踩

深刻了解JVM - 解读GC日志

次要内容还是以解说如何浏览日志,同时不同的机器运行的后果不同,文章更多的是介绍如何解读参数。

深刻了解JVM - 实战JVM工具(上)

这篇文章次要介绍一下罕用的JVM工具,当然介绍这些工具是没有意义的,因为不去应用吃个饭根本就会忘光,所以这篇文章次要为应用工具实操一下大抵如何监控和调优代码。

深刻了解JVM - 实战JVM工具(下)

  1. 介绍三个JVM调优的案例,一步一步剖析问题和解决办法。
  2. 总结剖析思路和解决流程,自我思考和反思。
  3. 总结和集体感想。

深刻了解JVM - 案例实战

  1. 排查Full Gc的套路是什么,这里用一个电商案例来进行阐明。
  2. spilt()办法是如何造成内存泄露的?如何通过可视化图形剖析出问题。以及如何从源代码层面发现基本问题

思维导图:

幕布地址:https://www.mubucm.com/doc/Ig...

概述

  1. 第二阶段的文章回顾和总结
  2. 你真的相熟老年代么?对象在什么时候会进入到老年代?
  3. 频繁的FULL GC通常有什么起因
  4. 优化JVM须要留神哪些点?

你真的相熟老年代回收么?

传统的JVM模型采纳固定分代的模式,首先咱们来回顾一下老年代的回收触发条件。

对象什么时候进入老年代

新生代是如何回收内存的?

讲述老年代回收之前,咱们回顾一下新生代是如何分配内存的,没错,就是采纳的 改进复制算法,新生代应用的是eden+2个survior区域进行内存的布局,默认状况下是8:1:1,这个值是能够扭转的,咱们能够应用参数:-XX:SurvivorRatio=8进行扭转,最初咱们来看下他的结构图:

改进复制算法在eden区域占满之后,触发一次YGC,会把存活对象复制到S1区域,之后清空掉整个eden区,这个过程是十分快的,而到了下一次YGC,会把S1中的存活对象和Eden区域的存活对象复制到S2区域,并且清空掉S1区域和EDEN区域。所以新生代回收的特点是:内存分为三块区域,每次只应用其中的两块,留存一块作为备用切换

以上是新生代的回收流程。当新生代触发YGC的时候,存活对象依据动静判断条件会进入老年代,那么老年代的FULL GC是如何解决的?他的触发条件是什么?这里的内容要重复回顾,因为非常的重要:

  1. 一个对象躲过了15次垃圾回收,年龄一到就进入老年代
  2. 对象超过新生代的总大小,超过肯定的阈值,会间接往老年代调配
  3. 一次Young GC之后存活对象太多了,因为Survior区域无奈寄存,这批对象间接进入老年代
  4. 对象进入到Survior区域之后,Survior忽然发现对象的占用内容超过50%,此时会依据年龄排序,把大于Survior区域的50%的年龄N的对象进入老年代,比方年龄2,3,4的对象,年龄为3的对象占比超过50%,意味着年龄3、4会进入老年代。

老年代GC是如何触发的?

老年代的FULL GC如何触发呢,在之前的文章有表格讲述触发老年代的工夫,这里再次总结一下:

  • 在CMS收集器,老年代本身有一个阈值,在JDK6之后默认是占满老年代空间92%之后将会进行触发。然而须要留神的是这个百分比不是固定的,在JVM中会依据理论的老年代占用状况提前完成垃圾回收。
  • YGC之前,会先判断老年代最大间断可用内存空间大小是否大于新生代历次进入老年代的均匀大小,如果不符合要求会在YGC之前触发一次FULL GC,回收掉一部分老年代对象,而后执行YGC。
  • 如果YGC存活对象太多,Survior区域放不下,如果要放入老年代,要是此时老年代也放不下,就会触发Full GC,回收老年代一批对象,再把这些年老代的存活对象放入老年代中。

失常状况下一班多少次GC:

失常状况下FULL GC的频率在几十分钟一次,几小时一次,这个GC频率还算是比拟能够承受的,当然每次FULL GC最好在几百毫秒内。

如果线上的零碎有这个体现根本不须要太关怀优化的问题。

如何察看JVM内存模型:

剖析手法:

这里能够依照上面的过程进行剖析:

  • EDEN区域的对象增长速率有多快?
  • YGC的频率有多高
  • 一次YGC多长的耗时
  • 老年代增长的速率多高
  • Full GC频率多高
  • 一次Full GC耗时

频繁FULL GC的几种体现:

  • 机器CPU负载高
  • 频繁FULL GC报警
  • 零碎无奈解决申请或者过慢。

频繁FULL GC个别有哪些起因:

之前讲述的案例比拟多,这里集中解说以下:

  1. 零碎承载高并发申请,或者解决数据量过大,导致YGC频繁,YGC过后对象太多,内存调配不合理,Survior区域过小,对象频繁进入老年代,频繁FULL GC
  2. 零碎短时间加载大量的对象,呈现很多长寿大对象,并且新生代无奈寄存只能进入老年代,必然频繁FULL GC
  3. 内存泄露,莫名其妙创立大量对象,导致对象无奈回收,并且占用老年代无奈回收,也会触发FULL GC
  4. 永恒代加载过多类导致的FULL GC,少数状况是因为反射的谬误应用导致。
  5. 误调用System.gc()

优化JVM应该留神点:

  • 最好有一套JVM通用模板:这里不是指轻易百度一套模板就拿来用,而是要依据以后的系统分析得业务零碎会产生多少对象名字啊什么时候会产生FULL GC,新生代要调配多少内存,老年代要调配多少内存
  • 不要轻易DUMP日志:本人试验能够轻易用,然而一旦到了线上环境,不仅须要找运维沟通,应用这个命令须要在业务拜访流量的低峰的时候再应用,须要十分小心谨慎的看待。