系统内存CPU过高分析思路

本文档整理来自网络,如有侵权,请留言告知

CPU过高查看

  1. 通过top命令查看占用cpu过高的进程,默认是进程模式

    top
    
  2. 键入大写P,按照cpu占用情况排序

  3. 查看cpu占用靠前的进程,比如排名第一的进程为8888

  4. 键入q或者ctrl+c退出top命令

  5. 通过top -Hp pid 查看该进程对应的所有线程资源占用情况

    # H参数表示进入线程模式,显示的是线程级别的资源占用情况
    # p表示通过进程id查看
    top -Hp 8888
    
  6. 键入大写P,按照cpu占用情况排序

  7. 查看cpu占用靠前的线程,比如排名第一的线程9999

  8. 通过jstack -l pid 命令输出dump信息

    # l参数表示输出长列表信息,如关于锁的附加信息
    jstack -l 8888 > stack_8888.dump
    
  9. vi stack_8888.dump查看线程9999的栈信息

    # 获取线程id的16进制码270f
    printf "%x\n" 9999
    
    # 查看270f对应的栈信息并进行分析,你将会找到nid=0x270f的栈信息
    vi stack_8888.dump 搜索270f
    
  10. 分析线程栈

    1.死锁,Deadlock
    2.执行中,Runnable
    3.等待资源,Waiting on condition
    4.等待获取监视器,Waiting on monitor entry
    5.暂停,Suspended
    6.对象等待中,Object.wait()或TIMED_WAITING
    7.阻塞,Blocked
    8.停止,Parked
    

线程栈分析

1、死锁,Deadlock(重点关注)
2、执行中,Runnable
3、等待资源,Waiting on condition(重点关注)
4、等待获取监视器,Waiting on monitor entry(重点关注)
5、对象等待中,Object.wait() 或 TIMED_WAITING
6、暂停,Suspended
7、阻塞,Blocked(重点关注)
8、停止,Parked

Runnable

线程正在运行中,一般指该线程正在执行状态中,该线程占用了资源,正在处理某个请求,有可能正在传递SQL到数据库执行,有可能在对某个文件操作,有可能进行数据类型等转换

Deadlock

线程死锁,下面是一个典型的死锁堆栈,t1线程lock在地址0x22a297a8,同时t2线程在waiting to lock这个地址,更有意思的是,堆栈也记录了发生死锁的代码行数,这对我们定位问题起到很大的帮助

"t2" prio=6 tid=0x02bcf000 nid=0xc70 waiting for monitor entry [0x02f6f000] 
 java.lang.Thread.State: BLOCKED (on object monitor) 
 at com.demo.DeadLock$2.run(DeadLock.java:40) 
 - waiting to lock <0x22a297a8> (a java.lang.Object) 
 - locked <0x22a297b0> (a java.lang.Object) 
 Locked ownable synchronizers: 
 - None 
"t1" prio=6 tid=0x02bce400 nid=0xba0 waiting for monitor entry [0x02f1f000] 
 java.lang.Thread.State: BLOCKED (on object monitor) 
 at com.demo.DeadLock$1.run(DeadLock.java:25) 
 - waiting to lock <0x22a297b0> (a java.lang.Object) 
 - locked <0x22a297a8> (a java.lang.Object) 
 Locked ownable synchronizers: 
 - None

Wait on condition

等待资源,或等待某个条件的发生,具体原因需结合stacktrace来分析,常见情况是该线程在sleep,等待sleep的时间到了时候,将被唤醒

1、常见情况是该线程在sleep,等待sleep的时间到了时候,将被唤醒。关键字:timed_waiting,sleeping,parking。TIMED_WAITING可能是调用了有超时参数的wait所引起的。parking指线程处于挂起中,下面是一个典型的sleep引起的Wait on condition:

"thread-1" prio=10 tid=0x00007fbe985cd000 nid=0x7bc6 waiting on condition [0x00007fbe65848000]
     java.lang.Thread.State: TIMED_WAITING (sleeping)
     at java.lang.Thread.sleep(Native Method)
     at com.xxx.MonitorManager$2.run(MonitorManager.java:124)
     at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
     at java.lang.Thread.run(Thread.java:662)

2、如果发现有大量的线程都在处在 Wait on condition,从线程 stack看,正等待网络读写,这可能是一个网络瓶颈的征兆,因为网络阻塞导致线程无法执行。一种情况是网络非常忙,几乎消耗了所有的带宽,仍然有大量数据等待网络读写;另一种情况也可能是网络空闲,但由于路由等问题,导致包无法正常的到达,可以结合其他网络分析工具定位问题,如下面的堆栈,线程等待在LinkedBlockingQueue上等待数据的生成

"IoWaitThread" prio=6 tid=0x0000000007334800 nid=0x2b3c waiting on condition [0x000000000893f000]
     java.lang.Thread.State: WAITING (parking)
     at sun.misc.Unsafe.park(Native Method)
     - parking to wait for  <0x00000007d5c45850> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
     at java.util.concurrent.locks.LockSupport.park(LockSupport.java:156)
     at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1987)
     at java.util.concurrent.LinkedBlockingDeque.takeFirst(LinkedBlockingDeque.java:440)
     at java.util.concurrent.LinkedBlockingDeque.take(LinkedBlockingDeque.java:629)
     at com.xxx.ThreadIoWaitState$IoWaitHandler2.run(ThreadIoWaitState.java:89)
     at java.lang.Thread.run(Thread.java:662)

Waiting on monitor entry

Object.wait()

线程在等待进入一个临界区

1、所有期待获得锁的线程,在锁已经被其它线程拥有的时候,这些期待获得锁的线程就进入了Object Lock的entry set区域
2、所有曾经获得过锁,但由于其它必要条件不满足而需要wait的时候,线程就进入了Object Lock的wait set区域
3、在wait set区域的线程获得notify/notifyAll通知的时候,随机的一个Thread(notify)或者是全部的Thread(notifyALL)从Object Lock的wait set区域进入了entry set中
4、在当前拥有锁的线程释放掉锁的时候,处于该Object Lock的entryset区域的线程都会抢占该锁,但是只能有任意的一个Thread能取得该锁,而其他线程依然在entry set中等待下次来抢占到锁之后再执行
5、看下面的堆栈,线程在等待数据库连接池返回一个可用的链接

" DB-Processor-13" daemon prio=5 tid=0x003edf98 nid=0xca waiting for monitor entry [0x000000000825f000]
java.lang.Thread.State: BLOCKED (on object monitor)
 at beans.ConnectionPool.getConnection(ConnectionPool.java:102)
 - waiting to lock <0xe0375410> (a beans.ConnectionPool)
 at xxx.getTodayCount(ServiceCnt.java:111)
 at xxx.ServiceCnt.insertCount(ServiceCnt.java:43)
"DB-Processor-14" daemon prio=5 tid=0x003edf98 nid=0xca waiting for monitor entry [0x000000000825f020]
java.lang.Thread.State: BLOCKED (on object monitor)
 at beans.ConnectionPool.getConnection(ConnectionPool.java:102)
 - waiting to lock <0xe0375410> (a beans.ConnectionPool)
 at xxx.ServiceCnt.getTodayCount(ServiceCnt.java:111)
 at xxx.ServiceCnt.insertCount(ServiceCnt.java:43)
" DB-Processor-3" daemon prio=5 tid=0x00928248 nid=0x8b waiting for monitor entry [0x000000000825d080]
java.lang.Thread.State: RUNNABLE
 at oracle.jdbc.driver.OracleConnection.isClosed(OracleConnection.java:570)
 - waiting to lock <0xe03ba2e0> (a oracle.jdbc.driver.OracleConnection)
 at beans.ConnectionPool.getConnection(ConnectionPool.java:112)
 - locked <0xe0386580> (a java.util.Vector)
 - locked <0xe0375410> (a beans.ConnectionPool)
 at xxx.Cue_1700c.GetNationList(Cue_1700c.java:66)
 at org.apache.jsp.cue_1700c_jsp._jspService(cue_1700c_jsp.java:120)

Blocked

线程阻塞,是指当前线程执行过程中,所需要的资源长时间等待却一直未能获取到,被容器的线程管理器标识为阻塞状态,可以理解为等待资源超时的线程。如果线程处于Blocked状态,但是原因不清楚。可以使用jstack -m pid得到线程的mixed信息,例如,以下信息表明,线程在尝试进入同步块时阻塞了

----------------- t@13 -----------------
0xff31e8b8      ___lwp_cond_wait + 0x4
0xfea8c810      void ObjectMonitor::EnterI(Thread*) + 0x2b8
0xfeac86b8      void ObjectMonitor::enter2(Thread*) + 0x250

内存过高查看

  1. 通过top命令查看占用内存过高的进程,默认是进程模式

    top
    
  2. 键入大写M,按照内存占用情况排序

  3. 查看内存占用靠前的进程,比如排名第一的进程为8888

  4. 键入q或者ctrl+c退出top命令

  5. 通过jmap命令导出dump文件,最后一个参数是pid

    jmap -dump:format=b,file=/data/logs/heap_8888.dump 8888
    
  6. 通过Memory Analyzer Tool等一些三方工具导入heap_8888.dump文件进行分析,安装及分析过程,此处不再赘余,自行百度:https://www.jianshu.com/p/c6e2abb9f657

你可能感兴趣的:(系统内存CPU过高分析思路)