Java问题排查的一些思路:cpu高、fgc多

前言

平时虽然碰到一些问题,但是排查起来也有些没有头绪,总结一下,理清思绪。

jstack 、jmap 、Jstat

  • jstack能得到运行java程序的java stack和native stack的信息。可以轻松得知当前线程的运行情况。

  • jmap: 得到运行java程序的内存分配的详细情况。例如实例个数,大小等 。

  • Jstat:这是一个比较实用的一个命令,可以观察到classloader,compiler,gc相关信息。可以时时监控资源和性能 。

java 占用CPU高,怎么得到具体的线程?

第一步:找到Java进程

  • 1、top 命令
  • 2、ps -ef | grep java

这两个命令随便可以都可以帮助你找到Java进程,最好用top命令

第二步:找到确定的Java 进程之后 就可以 通过命令来看看进程信息

  • 1、top -Hp pid
  • 2、Ps -mp pid -o THREAD,tid,time

这其中 pid 就是进程号,可惜这没有排序,得自己一个一个看,如果非要排序,自己改写一下命令,我暂时还不熟悉,没得办法。当然这个语句不能在Mac book 上运行,这为此我还浪费了一些时间。这样就找到了具体的线程了。

怎么查看 为什么 CPU高呢?

由于jstack.log文件记录的线程ID是16进制,需要将top命令展示的线程号转换为16进制:

printf "%x\n" 15100

15100 的16进制是3afc,然后可以通过命令来看下线程名称:

jstack 8958 | grep 3afc -A 50

8958是进程号,这样看可能还看不出来具体的代码位置,可以通过一下命令来将数据打印到文件中查看:

jstack -l  8958 >> 123.txt

可以打印整个进程信息,其中包括进程下所有线程的信息,一些线程信息供大家参考:

"pool-1617252-thread-1" prio=10 tid=0x00007f76a00e5800 nid=0x3afc runnable [0x00007f7658e61000]
   java.lang.Thread.State: RUNNABLE
        at java.util.Random.next(Random.java:139)
        at java.util.Random.nextDouble(Random.java:394)
        at java.lang.Math.random(Math.java:695)
        at com.xxx.xxx.utils.Rand.randomNoSame(Rand.java:100)
        at com.xxx.xxx.videos.GetVideoListService.getUserPullDownVirtualPageResult(GetVideoListService.java:275)
        at com.xxx.xxx.videos.GetVideoListService.getVideoList(GetVideoListService.java:94)
        at sun.reflect.GeneratedMethodAccessor1123.invoke(Unknown Source)

其中:

  • 第一行表示线程信息,后面的代码是Java thread statck trace,应该从下往上看。
  • nid= 0x3afc 就是#对应系统线程id(NativeThread ID),这个线程就是我们用TOP命令查询出来的系统线程
  • tid表示 JVM线程id:tid=0xac190c00,JVM内部线程的唯一标识(通过java.lang.Thread.getId()获取,通常用自增方式实现)。

可以看到线程的内容。

Java 线程状态

  • NEW:
    每一个线程,在堆内存中都有一个对应的Thread对象。Thread t = new Thread();当刚刚在堆内存中创建Thread对象,还没有调用t.start()方法之前,线程就处在NEW状态。在这个状态上,线程与普通的java对象没有什么区别,就仅仅是一个堆内存中的对象。

  • RUNNABLE:
    该状态表示线程具备所有运行条件,在运行队列中准备操作系统的调度,或者正在运行。 这个状态的线程比较正常,但如果线程长时间停留在在这个状态就不正常了,这说明线程运行的时间很长(存在性能问题),或者是线程一直得不得执行的机会(存在线程饥饿的问题)。

  • BLOCKED:
    线程正在等待获取java对象的监视器(也叫内置锁),即线程正在等待进入由synchronized保护的方法或者代码块。synchronized用来保证原子性,任意时刻最多只能由一个线程进入该临界区域,其他线程只能排队等待。

  • WAITING:
    处在该线程的状态,正在等待某个事件的发生,只有特定的条件满足,才能获得执行机会。而产生这个特定的事件,通常都是另一个线程。也就是说,如果不发生特定的事件,那么处在该状态的线程一直等待,不能获取执行的机会。

  • TIMED_WAITING:
    J.U.C中很多与线程相关类,都提供了限时版本和不限时版本的API。TIMED_WAITING意味着线程调用了限时版本的API,正在等待时间流逝。当等待时间过去后,线程一样可以恢复运行。如果线程进入了WAITING状态,一定要特定的事件发生才能恢复运行;而处在TIMED_WAITING的线程,如果特定的事件发生或者是时间流逝完毕,都会恢复运行。

  • TERMINATED:
    线程执行完毕,执行完run方法正常返回,或者抛出了运行时异常而结束,线程都会停留在这个状态。这个时候线程只剩下Thread对象了,没有什么用了。

内存高 线程

其实通过上述过程,也可以看到内存指标,大家可以参考这个数据,但这个指标其实是没有实质含义的,因为线程内存都是共享的,因为JVM内存模型中的Java heap 就是线程共享的。

FGC 排查思路

其实通过jstat 命令可以查看内存区的使用情况,查看年轻代、老年代的内存占比,YGC、FGC的次数,命令大概是:

jstat -gcutil 110792 250 3

其中 :

  • gcutil 表示查看gc情况,GC统计汇总
  • 110792 表示Java进程号
  • 250 表示每过250毫秒打印一次
  • 3 表示打印次数

用网上的图来表示为:

其中:

  • E:年轻代,数字表示占比
  • O:老年代,数字表示占比
  • FGC:次数,程序启动后到现在的次数

这个图比较恶心了一点,都是100%占有,而且FGC都是几乎1s一次。直接下载内存信息出来看下吧

jmap -F -dump:format=b,file=heapDump 1   # 1 是进程号

查看内存信息,通过mat工具来查看内存信息。看top 1的对象使用或者自己定义的对象使用情况,有时候看内存对象信息就可以找出问题,其他的特殊情况就要具体的手段了 。

死锁

对于死锁,这种情况基本上很容易发现,因为jstack可以帮助我们检查死锁,并且在日志中打印具体的死锁线程信息。如下是一个产生死锁的一个jstack日志示例:

jstack pid

参考博客

java命令–jstat 工具使用
系统运行缓慢,CPU 100%,以及Full GC次数过多问题的排查思路

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值