深刻了解 JVM – 阶段总结与回顾(二)
前言
上一文为:深刻了解 JVM – 阶段总结与回顾(一),阶段总结一次要内容为 JVM 的一些调优常识储备以及后面的文章回顾,这一节将会总结一些 JVM 常见的调优套路,帮忙大家在理论状况中遇到问题的时候不用慌乱,这里要特别强调一点:平时写代码要常常回顾和逻辑梳理,对于一些不确定的办法肯定要点开源码进行解读。
之前有评论说思维导图更直观一些,所以后续的文章都会尽量附上思维导图节俭大家的工夫。
前文回顾:
上一节咱们给了两个简略的案例,解说了 FULL GC 的常见排查套路,依据排查套路能够帮忙咱们疾速找到排查的方向并且及时的定位到真正的问题点,这对于排查线上问题是一项很重要的技能。
另外咱们还讲述了 String.split()
是如何让 JVM 频繁进行 FULL GC 的,咱们用图表一步步剖析出基本后果,并且解读源码剖析了这个办法在 JDK 版本升级的改变,因为降级后源代码在切割字符串之后创立 SubList 对象(底层为数组)导致这一问题的产生,这里 JDK 要背一部分锅,因为它违反了 向下兼容 这一规定,然而更多状况下是因为开发人员对于办法理解水平不够,最终导致代码逻辑产生内存透露!
以上就是上一节的所有内容。
阶段总结:
在个人主页也有历史文章,欢送来踩
深刻了解 JVM – 解读 GC 日志
次要内容还是以解说如何浏览日志,同时不同的机器运行的后果不同,文章更多的是介绍如何解读参数。
深刻了解 JVM – 实战 JVM 工具(上)
这篇文章次要介绍一下罕用的 JVM 工具,当然介绍这些工具是没有意义的,因为不去应用吃个饭根本就会忘光,所以这篇文章次要为应用工具实操一下大抵如何监控和调优代码。
深刻了解 JVM – 实战 JVM 工具(下)
- 介绍三个 JVM 调优的案例,一步一步剖析问题和解决办法。
- 总结剖析思路和解决流程,自我思考和反思。
- 总结和集体感想。
深刻了解 JVM – 案例实战
- 排查 Full Gc 的套路是什么,这里用一个电商案例来进行阐明。
- spilt()办法是如何造成内存泄露的?如何通过可视化图形剖析出问题。以及如何从源代码层面发现基本问题
思维导图:
幕布地址:https://www.mubucm.com/doc/Ig…
概述
- 第二阶段的文章回顾和总结
- 你真的相熟老年代么?对象在什么时候会进入到老年代?
- 频繁的 FULL GC 通常有什么起因
- 优化 JVM 须要留神哪些点?
你真的相熟老年代回收么?
传统的 JVM 模型采纳固定分代的模式,首先咱们来回顾一下老年代的回收触发条件。
对象什么时候进入老年代
新生代是如何回收内存的?
讲述老年代回收之前,咱们回顾一下新生代是如何分配内存的,没错,就是采纳的 改进复制算法 ,新生代应用的是 eden+ 2 个 survior 区域进行内存的布局,默认状况下是 8:1:1,这个值是能够扭转的,咱们能够应用参数:-XX:SurvivorRatio=8 进行扭转,最初咱们来看下他的结构图:
改进复制算法在 eden 区域占满之后,触发一次 YGC,会把存活对象复制到 S1 区域,之后清空掉整个 eden 区,这个过程是十分快的,而到了下一次 YGC,会把 S1 中的存活对象和 Eden 区域的存活对象复制到 S2 区域,并且清空掉 S1 区域和 EDEN 区域。所以新生代回收的特点是:内存分为三块区域,每次只应用其中的两块,留存一块作为备用切换
以上是新生代的回收流程。当新生代触发 YGC 的时候,存活对象依据动静判断条件会进入老年代,那么老年代的 FULL GC 是如何解决的?他的触发条件是什么?这里的内容要重复回顾,因为非常的重要:
- 一个对象躲过了 15 次垃圾回收,年龄一到就进入老年代
- 对象超过新生代的总大小,超过肯定的阈值,会间接往老年代调配
- 一次 Young GC 之后存活对象太多了,因为 Survior 区域无奈寄存,这批对象间接进入老年代
- 对象进入到 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 个别有哪些起因:
之前讲述的案例比拟多,这里集中解说以下:
- 零碎承载高并发申请,或者解决数据量过大,导致 YGC 频繁,YGC 过后对象太多,内存调配不合理,Survior 区域过小,对象频繁进入老年代,频繁 FULL GC
- 零碎短时间加载大量的对象,呈现很多 长寿大对象,并且新生代无奈寄存只能进入老年代,必然频繁 FULL GC
- 内存泄露,莫名其妙 创立大量对象,导致对象无奈回收,并且占用老年代无奈回收,也会触发 FULL GC
- 永恒代 加载过多类 导致的 FULL GC,少数状况是因为反射的谬误应用导致。
- 误调用System.gc()
优化 JVM 应该留神点:
- 最好有一套 JVM 通用模板:这里不是指轻易百度一套模板就拿来用,而是要依据以后的系统分析得业务零碎会产生多少对象名字啊什么时候会产生 FULL GC,新生代要调配多少内存,老年代要调配多少内存
- 不要轻易 DUMP 日志:本人试验能够轻易用,然而一旦到了线上环境,不仅须要找运维沟通,应用这个命令须要在业务拜访流量的低峰的时候再应用,须要十分小心谨慎的看待。