找回密码
 会员注册
查看: 17|回复: 0

谜!JVM为何僵死

[复制链接]

2万

主题

0

回帖

6万

积分

超级版主

积分
64454
发表于 2024-10-10 21:10:20 | 显示全部楼层 |阅读模式
谜!JVM为何僵死 谜!JVM为何僵死 吴玲 贝壳产品技术 贝壳产品技术 “贝壳产品技术公众号”作为贝壳官方产品技术号,致力打造贝壳产品、技术干货分享平台,面向互联网/O2O开发/产品从业者,每周推送优质产品技术文章、技术沙龙活动及招聘信息等。欢迎大家关注我们。 242篇内容 2017年07月16日 17:01 此文作者吴玲,链家网二手技术中心-业务架构部的负责人,我司JAVA大牛,江湖人称玲姐(然而并不是妹子)。此文是玲姐在帮助兄弟部门排查一个Java应用莫名僵死问题的过程总结,希望对大家有帮助。作者|吴 玲编辑|蔡白银网址|tech.lianjia.com微信公众号|链家产品技术团队前言前不久有兄弟部门的同事找到我,说他们有一个Java应用偶尔会莫名僵死、无响应、同时有个CPU核心占用100%,不稳定复现。希望我协助看看是什么原因。现场如果仅仅只看到“僵死”,“无响应”这类描述,可能马上想到GC可能有问题,又看到CPU占用100%,又可能是存在死循环,实际情况是怎么样的呢?咱们要用证据来说话,所谓证据其实就是故障现场,包括但不限于:GC日志、线程dump、堆dump、业务日志、CPU、内存、磁盘等资源使用情况等等。1. thread dump就这个问题而言,因为CPU占用飙到100%,所以我们先通过线程dump出来的堆栈信息看看线程都在干什么。一般情况下我们常用jstack命令来获取线程dump。同事先使用了如下命令,结果命令也僵死无响应:去掉-l后才dump出了咱们的第一个证据, 内容大致如下:查看以上信息,发现了一个很奇怪的现象,除了监听端口的主线程外,所有的线程都处于BLOCKED状态,并且调用栈上没有任何业务代码的痕迹。但是为什么CPU会占用100%呢?一个合理的推测是存在其他正在执行本地方法的线程,然后我让同事分别用查看到占用CPU100%的线程调用栈如下:这个调用栈信息,看起来像是在遍历类结构的时候出现了死循环,目测可能是触发了JVM的隐藏BUG2.GC STAT除了查看GC日志外,一般我们还经常通过jstat来查看gc情况,比如:注意看M的那一列,代表Metaspace的使用已经接近100%,而Metaspace是从java8开始引入,替代过去的PermGen空间(永久带),用来存放类的元数据等信息3.JVM 启动参数精简后的JVM启动参数如下:从启动参数可以看出来:1. jdk版本是HotSpot 8u402. 指定了MaxMetaspaceSize3. 使用了CMS GC算法、增量模式4. 指定了noclassgc分析处理线上问题,最要紧的一定是先尽快恢复服务,减少业务损失。从之前的信息来推测,大概率是触发了JVM的隐藏BUG,从历史来看,hotspot bugfix的速度还是不错的,同事先升级到最新的JDK版本尝试恢复服务,咱们再接下来分析原因。MaxMetaspaceSize顾名思义,通过这个选项指定Metaspace空间的最大值。当超过这个值时,将会触发GC对该空间进行回收。CMSClassUnloadingEnable这个选项的含义是当使用CMS算法时,是否进行类卸载(ClassUnloding)。jdk6和jdk7的默认值都是false,从Jdk8开始默认值变为了true,也就是默认进行类卸载。noclassgc这个选项的含义是不对class进行GC,哪怕这些class已经成为垃圾。实际等价于不进行类卸载。现在相当于同时打开了CMSClassUnloadingEnable和noclassgc,那到底类还会不会被卸载呢?我们来看看Openjdk 8u40的源码[1]里对这两个选项的使用(虽然openjdk跟hotspot的代码有些差别,但大部分逻辑是一样的):A.globals.hpp L1710将CMSClassUnloadingEnabled默认设置为trueB.arguments.cppL2786当指定了-Xnoclassgc后实际是将ClassUnloading设置为falseC.concurrentMarkSweepGeneration.cppL6262当需要卸载类时,会去更新类的层次结构(class hierarchy),将卸载的类从对应的链表里删除D.concurrentMarkSweepGeneration.cpp#update_should_unload_classes什么时候需要卸载类呢?从这个方法实现可以看到,是否进行类卸载有两个条件,跟CMSClassUnloadingEnabled和ExplicitGCInvokesConcurrentAndUnloadsClasses有关,但跟ClassUnloading无关E.kclass.cpp#clean_weak_klass_links当ClassUnloading为false时,并不会去更新类的层次结构原因所以原因基本上就呼之欲出了,CMS下,类卸载包含关键的三步:Unload classes and purge the SystemDictionary.Unload nmethods.Prune dead klasses from subklass/sibling/implementor lists.当CMSClassUnloadingEnabled为true,ClassUnloading为false时, 实际只完成了前两步,而第三步未完成。也就是说CMSClassUnloadingEnabled跟ClassUnloading冲突了。同事那边升级了新版的jdk后没有再出现过问题。我去翻了一下jdk的bugfix list,发现在8u60[2]的时候已经fix掉了这个bug[3],修复的方法也很简单[4]:当ClassUnloading为false时,将CMSClassUnloadingEnabled和ExplicitGCInvokesConcurrentAndUnloads也设置为false.启示保存好故障现场后及时恢复业务、再进行排查分析不要随便使用自己没掌握的参数选项。及时升级你jdk的小版本,从bugfix的list也可以看出来,其实jdk的bug也不 少 HotSpot的启动参数非常之多,实际使用也分散在代码里的各个角落,几乎没有人能完全搞清楚各个参数之间是否会有冲突,从易用性上来说,确实比不上JRocket和Zing。后语其实文章里挖了一些小坑没填,我实在很懒,就当作小作业留给你去解答吧 [1]http://hg.openjdk.java.net/jdk8u/jdk8u40/hotspot/file/68577993c7db/src[2]http://www.oracle.com/technetwork/java/javase/2col/8u60-bugfixes-2620228.html[3]http://bugs.java.com/view_bug.dobug_id=8085965[4]http://hg.openjdk.java.net/jdk9/jdk9/hotspot/rev/8c0e5aa4995e 预览时标签不可点 关闭更多小程序广告搜索「undefined」网络结果
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2024-12-27 01:50 , Processed in 0.463246 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表