JVM调优学习笔记

一、程序中难以调试的bug

1.野指针

        - 同一个对象,两个指针,一个指针将对象释放释放,另一个指针报NPE

        - 同一个对象,两个指针,一个指针将对象释放释放,新对象占用原对象未知,另一个指针指向新对象

2.并发问题

        - 多线程访问同一个块内存空间

二、垃圾清除算法

Mark-Sweep 标记清除:将垃圾标记之后清除,但会产生碎片化问题

Copying 拷贝:将存活对象收集排列好复制到另一块区域,但会浪费内存

Mark-Compact 标记压缩:在清理垃圾的时候顺便排列存活对象,但效率低

三、堆内存逻辑分区

新生代:采用Copying,频繁GC

老年代:采用Mark-Sweep与Mark-Compact,满了进行FGC

四、GC演化:

1.几兆到几十兆:

        - Serial:首先STW(主线程停止),再将未使用垃圾回收。年轻代(采用Copying)

        - Serial Old:首先STW(主线程停止),再将未使用垃圾回收。老年代(采用Mark-Sweep与Mark-Compact)

        新生代和老年代都使用单线程

2.几十兆到上百兆:

        - parallel Scavenge:首先STW(主线程停止),再将未使用垃圾回收

        - Parallel Old:首先STW(主线程停止),再将未使用垃圾回收

        新生代和老年代都使用多线程并行

3. 1G到数十G:

        - Concurrent GC:也会进行STW,但由于多线程,等待时间较短

        主要过程

                - 初始标记:STW,从根开始寻找

                - 并发标记:业务线程不停止,垃圾回收线程标记垃圾

                - 重新标记:STW,由于运行过程中存在错标需要修正,即对象再引用和对象不引用

                - 并发清理:多线程清理垃圾

CMS:

三色标记算法:运用于并发标记阶段

        黑:本对象及其引用的其他对象都访问过。下一次不会扫描该节点

        灰:本对象已访问,但其引用对象为全部访问。下一次从未扫描的节点开始

        白:未访问的对象

        问题:(灰->白)由于线程运行变为(黑->白),此时通过Incremental Update方案,把黑转为灰。但多线程情况下,可能会出现线程1认为黑仍为黑,线程2将黑转灰,但是最终线程1仍将黑标为黑,即出现错误。

        注:->表示指向

Epsilon:只做标记。可用于JVM调优debug

G1:物理上不再区分年轻代和老年代,都是以一小块区域存在。逻辑上分区,某块区域在回收之后重新分配可能是伊甸区,s1,s2,也可能是老年区

五、处理漏标方法

CMS:写屏障+增量更新        G1:写屏障+SATB        ZGC:读屏障

最小堆内存和最大堆内存保持一致可以避免内存抖动

六、调优案例:

OLD GC耗时较长:

        原因:Remark阶段时间较长

        优化:-XX:+CMSScavengeBeforeRemark  在重新标记前再进行一次YGC以减少存活对象

YGC耗时增加:

        原因:jackson进行反序列化时会将key进行String#intern,导致扫描时,GCRoot变大

        解决:禁用jackson的String#intern(String常量池)

YGC次数增加:

        原因:-XX:MaxGCPauseMillis参数时间设置过小,导致JVM降低年轻代region

        解决:1.调大-XX:MaxGCPauseMillis的值  2.将年轻代region大小设置为固定值

CMS内存碎片化导致FGC:

        原因:由于CMS通过标记清除的方法回收垃圾,不进行压缩与整理,会出现碎片化问题,影响大对象的分配,长期之后会出现FGC

        优化策略:业务低峰期显式触发FGC,以降低在业务高峰期出现FGC概率

                System.gc() 注:没有开启-XX:+DisableExplicitGC,否则失效

                Jmap -histo:live pid

YGC和OLD GC频繁:

        原因:为了降低服务时延,让YGC较快完成,年轻代设置较小,但造成YGC过多。年轻代设置较小又导致大量对象较早进入老年代,从而导致OLD GC频繁

        优化:扩大新生代内存 (虽然单次YGC耗时增加,但是频率大大降低,OLD GC频率也会下降许多)

metaspace导致频繁FGC:

        原因:反射调用导致创建大量DelegatingClassLoader,占用较大元空间内存,同时存在碎片化问题,导致元空间利用率不高,触发FGC

      优化:1.调大metaspace空间的大小  2.优化不合理的反射调用。如用mapstruct替换BeanUtils.copyProperties()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值