Java问题定位之如何借助线程堆栈进行问题分析

在大型的应用中,线程堆栈打印出来特别多,如何从众多的信息中找到真正有用,有价值的信息,我们需要一定的技巧。本文对此详细介绍。

我们可以从三个方面分析:堆栈的局部信息,一次堆栈的统计信息,多个堆栈的对比信息。

  • 从一次的堆栈信息中,我们可以直接获取以下信息:
    • 每一个线程的调用关系,当前线程在调用哪些函数
    • 每个线程的当前状态,持有哪些锁,在等待哪些锁?
  • 从一次堆栈信息中,我们还可以统计以下信息:
    • 是否有很多线程都在等待同一个锁,说明这个系统存在性能瓶颈,导致了锁竞争
    • 当前线程的总数量
    • 大多数线程在干什么,在执行什么代码?
  • 从多次的堆栈信息中,可以得到以下信息:
    • 一个线程是否长期执行,如果每次打印堆栈某个线程一直处于同样的调用上下文中,那么说明这个线程一直执行这段代码,此时要根据代码逻辑检查,是否合理。
    • 某个线程是否长期存在获取不到锁的情况,线程是否永远得不到唤醒,如果某一个线程一直等在一个锁,就要检查占用这个锁的线程为什么不释放。

如果说打印一次线程堆栈是平面,那么打印多次就是立体了,我们可以看到一段运行的情况。

接下来从以下几个方面分析:

  • 线程死锁分析
  • java代码导致的cpu过高分析
  • 死循环分析
  • 资源不足分析性能瓶颈分析

线程死锁分析

线程死锁的原因:当两个或者多个线程正在等待被对方占用的锁,死锁就会发生。在时间0的时候,线程0占用lock0锁,线程1占用lock1锁。在时间1,进行了其它操作,在时间2,线程0,1企图持有对方的锁,但是由于2个锁已经在时间0被锁住,所以只能等待释放。由于这两个线程互相要等待被对方占有的锁,自己才能继续,因此就造成了死锁。

从打印的堆栈信息可以看到第一行,found one java-level deadlock ,如果线程存在死锁情况,堆栈会直接给出死锁的分析结果。从堆栈信息中可以看到,TestThread2中持有锁<0x22bffb10>但在等待锁<0x22bffb08>,相反,TestThread2中持有锁<0x22bffb08>,但在等待锁<0x22bffb10>。这里说的死锁是真正意义上的死锁,由于代码的错误导致的,严重程度取决于线程执行什么性质的功能代码,如果是关键功能,可能造成整个系统的瘫痪。死锁的2个或者多个线程是不消耗cpu的,所以认为死锁会导致cpu100%是错误的。

Java代码死循环等导致的cpu过高的分析

当系统负载大的时候会导致cpu过高,但不正确的代码也会导致cpu过高,比如死循环。我们如何从线程堆栈中找到死循环的线程呢?方法就是多次打印堆栈信息,通过对比前后的线程,找到一致运行的线程。具体步骤如下:

  1. 通过上一篇文章介绍过的方法打印第一次堆栈信息
  2. 等待一定时间,再次打印第二次堆栈信息
  3. 预处理2次堆栈信息,首先排除等待状态的线程,这种状态的线程不消耗cpu,前面已经讲过。我们只关注runnable状态的线程。
  4. 比较前后2次预处理后的线程,找出一段时间一直活跃的线程,如果2次堆栈信息在同一个线程处于同样的调用上下文,就列为重点怀疑对象。接下来结合代码逻辑检查该线程执行的上下文所对应的代码是不是属于应该长期运行的代码。

如果通过堆栈定位没有发现可疑代码,那么cpu高可能是不恰当的内存设置导致的频繁gc,从而导致的cpu过高。

资源不足等导致的性能下降分析

这里说的资源包括数据库连接。大多数时候资源不足和性能瓶颈是同一类问题。当资源不足,就会导致资源的竞争,请求该资源的线程会被阻塞或者挂起,自然就导致性能下降。系统对于资源,一般的设计模式是:当需要资源的时候,获取资源,当不需要的时候就把资源释放掉。如果暂时没有可用的资源,就等待在哪里。如果有别的线程释放资源,那么等待的线程被notify,等待的线程获得资源继续运行。一般的资源设计都遵循wait/notify模式。如果资源不足,那么有大量的线程等待资源,打印的线程堆栈如果具有这个特征,说明该资源存在瓶颈。

  1. 大量的线程停在同样的调用上下文上。
  2. 资源数量配置太小,如数据库连接数,如果系统压力过大,资源不足导致线程不能及时获得资源而等待在那里。
  3. 获得资源的线程把持资源时间太久,导致资源不足。比如把一段和操作数据库无关的代码放在获取数据库连接和释放数据库连接之间。
  4. 设计不合理导致的资源占用太久,比如sql没有加索引导致执行sql太慢。
  5. 资源用完后,没有关闭导致资源泄漏或者减少。

资源不足往往表现出一个现象是系统越来越慢,并最终停止响应,超时。

多个锁导致的锁链分析

很多线程在等待不同的锁,有的锁竞争可能是由于另一锁对象竞争导致,这时候需要找到根源。

  1. 看到有40多个线程在等待锁0xbef17078,首先找到已经占有这把锁的线程thread-196
  2. 看到thread-196占有锁,0xbef17078,但又在等待锁<0xbc7b4110>,那么此时需要再找占有<0xbc7b4110>这个锁的线程,即thread-609。
  3. 那么占有锁<0xbc7b4110>的线程是问题的根源,下一步就是查到底为什么这个线程长时间占有这个锁。可能的原因是持有这把锁的线程正在执行的代码性能比较低,导致占有时间过长。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容