JVM调优及各种问题处理

内存划分:

  1. moniorGC(年轻代)

  1. MajorGC(老年代)

  1. 元空间

  1. FullGC(收集整个堆)

FullGC的排查步骤

*检查JVM参数设置,JVM监控系统的各项指标

*查看fullGC后 老年代的内存空间是否收回(内存泄露)

*查看堆内存的各区域的使用率及GC情况

--jstat -gcutil -h20 pid 1000

*查看堆内存中的存活对象,并按空间排序

--jmap -histo pid | head -n20

*dump堆内存文件,用可视化的堆内存工具

--jmap -dump:format=b,file=heap pid

FullGC的触发条件:

  1. System.gc()方法的调用

  1. 当年轻代移动的次数大于设置的阈值

  1. 老年代的空间(连续空间)不足时

  1. 元空间内存到达阈值

  1. 堆中产生的大对象超过阈值直接放入老年区,导致老年代空间不足

总得来说就是:大多数情况下是老区老年代的空间不足或者连续空间不足导致的GC

JVM垃圾收集器

垃圾回收算法,ParNew CMS 与G1的区别

什么环境下可以使用G1替换ParNew+CMS(官方)

-实时数据占用了超过半数的堆空间

-对象分配率或“提升”的速度变化明显

-当GC的耗费的时间过长(0.5-1S)

CMS回收步骤:

*初始标记:stop the world

*并发标记

*重新标记: stw

*并发清理

G1回收步骤:

*初始标记:stw

*并发标记

*最终标记:stw

*筛选处理

G1的优缺点:

-模糊了分代的概率,用区域Region来替代,一般是1-32M,默认分为2048个空间

-高吞吐,低延迟

-可以根据用户设定的回收时间,产生对应的预测回收模型,在有限的时间内,尽量回收更多的内存空间

GC Roots过程存在的多标漏标的问题:

三色标记法:通过GCRoots使用三色标记算法去检查存活对象,对对象进行标记

三色标记法的标记过程:
  1. 初始的时候,所有对象都在【白色集合】中

  1. 将GC Roots直接引用的对象挪到【灰色集合】中

  1. 对【灰色集合】中对象操作

3.1将【灰色集合】中的本对象的引用也挪到【灰色集合】中

3.2 将【灰色集合】中的本对象挪到【黑色集合】中

  1. 重复步骤3,直到【灰色集合】中的对象为空

  1. 遍历结束后,扔在【白色集合】中的对象就是可以回收的

为什么使用三色标记法:

-避免STW现象,能并发的处理过程,减少中断时间或者没有中断来进行GC回收环节

三色分别为白色(未被检查的对象)、灰色(被初步检查,未完全检查完全,只扫描对象本身,未扫描引用的对象)、黑色(检查完全,已经扫描过它全部的引用对象)

发生问题场景:多标、漏标

-在GC回收过程中当应用线程与三色标记算法的GC一起运行的时候出现的多标、漏标问题

-多标-浮动垃圾:在遍历的过程中,原本的黑色对象A引用了对象B,此时在遍历灰色B的时候,A删除了对B的引用,然后此时B已经是灰色对象了,所以认为B是存活的对象,此轮检查就活了下来,需要等待下一轮的重新检查,在清理B。

-漏标(把原来存活的垃圾,标记成了死亡):有2个必要条件

  1. 至少有一个黑色对象在被扫描完之后对白色对象A产生了引用关系

  1. 灰色对象在被扫描的过程中,删除了对白色对象A的引用

解决漏标的方法:

CMS采用了增量更新的方式打破条件1:在黑色对象新增了白色对象A引用时,将黑色对象又重新置为了灰色对象,在下一轮的重新标记检查中重新扫描

G1采用原始快照的来打破条件2:在灰色对象断开白色对象引用的之前进行了快照,在删除引用后,对白色对象变为灰色对象,在下一轮的最终标记阶段对灰色对象重新进行扫描

增量更新跟原始快照的优缺点:

增量更新:不会产生浮动垃圾,效率低(因为扫描的时黑色对象的全部引用)

原始快照:会产生浮动垃圾(原本就应该被判定为垃圾的对象,会多存活一段时间),效率高(只对被删除引用的白色对象进行引用的扫描)

JVM常见问题:

-内存溢出(Out Of Memory):在申请内存的时候,JVM没有足够的内存分配

-内存泄露(Memory Leak):申请了内存的,但是没有释放回收,导致内存空间浪费

小知识点:内存泄露会导致出现内存泄露的问题,会报Out Of Memory Error异常,而内存泄露则不会直接报出异常,需要自己去定位排查问题。

内存溢出分为几种情况:

-堆溢出

排查方案--jmap查看内存占用情况,使用命令查看堆内对象的分配,对Dump出来的堆转储(JVM内存的某一个时刻的快照,生成一个.hprof的二进制文件,谨慎使用,因为在命令执行时间会暂停其它线程)内存快照进行分析

导致的原因--

  1. 创建了大量新建的对象或者大集合

  1. 使用了大量的循环或者死循环,或者无限递归

  1. 使用了过多的static修饰

  1. 存在很多对象的引用,导致对象不能被释放

-栈溢出

排查方案同上

-导致的原因

  1. 一般是死循环或者递归太深,请求的栈深度大于虚拟机所允许的最大深度

  1. 栈空间设置过小

-方法区溢出(<=JDK1.7)

排查方案同上

-导致的原因

  1. 出现大量的Class对象,类加载过多,常量池的对象太大

-元空间溢出(>=JDK1.8)

排查方案同上

-导致的原因

  1. 使用的是本地内存,大量的Class对象被出创建没有回收(方法中重复创建对象,又因为ClassLoder是主线程创建的,只要线程一直运行就不会被回收)

解决方案:重复使用一个对象,避免重复创建。给元空间设置合理的大小

小知识:堆外内存:也叫直接内存,不属于虚拟机运行时数据区,是一块由操作系统直接管理的内存,性能强于堆内存。使用场景:1.有很大的数据需要存储,生命周期很长2.频繁的IO操作

对象逃逸分析:分析对象动态作用域,当一个对象在方法中被定义后,它可能被外部方法所引用。

CPU突然飙高的解决方式:

  1. 通过top -p pid h 打印该进程下的所有线程,查看占用cpu资源高的线程ID

  1. printf“%x”,将十进程的线程id转化为十六进制的线程id

  1. jstack pid 找出占用cpu占用过高的线程id的线程信息

JVM调优:

主要是关注吞吐量跟响应时间

吞吐量 = 用户代码的执行时间/(用户代码的执行时间+GC执行时间)

响应时间 = 整个接口的响应时间(用户代码的执行时间+GC执行时间),stw越短(stop the world过程会暂停其它线程的运行),响应时间越短

调优内容:

  1. jvm参数设置符合自身业务需求跟性能最优

  1. 选择合适的垃圾收集器

  1. 目标就是减少GC的次数及GC的时间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

半生程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值