细心!用心!耐心!

吾非文人,乃市井一俗人也,读百卷书,跨江河千里,故申城一游; 一两滴辛酸,三四年学业,五六点粗墨,七八笔买卖,九十道人情。

BlogJava 联系 聚合 管理
  1 Posts :: 196 Stories :: 10 Comments :: 0 Trackbacks
之前看过一篇很不错文档(WLS的异常高CPU占用率分析诊断),原作英文版的,有幸看到,遗憾的是没保存,不过中文版翻译的也不错,在之前的dev2dev和OTN上都有那篇文档的中文版

原文对5种常见的操作系统下WLS的异常高CPU占用率分析都有,SUN-Solaris、HP-UX、IBM-AIX、MS-Windows上的都比较详细,唯独没看明白Linux平台上的分析,而且现在看来,那篇文章中关于查找占用CPU过高的内核进程号的地方一笔带过,周六、周末在家又认真的看了看Linux平台下的top和ps这两个常用命令的帮助,最终得已清晰,这里又加以补充,并作文档一篇跟大家共享,欢迎赐教。

一、进程、线程和轻量级进程(Lightweight,简称LWP)简述

进程是资源管理的最小单位,而线程又是程序执行的最小单位,一个进程至少需要一个线程作为它的指令执行体,进程管理着资源(比如CPU时间片、虚拟内存文件句柄、信号处理器等),线程可以共享这些资源。轻量级进程(LWP)是一种由内核支持的用户线程。


每一个进程有一个或多个LWP,而每个LWP都与一个特定的内核线程关联(这种线程模型就是LinuxThreads和NPTL(符合POSIX)共同所有的1:1[一对一]的模型),不过NPTL线程模型中,进程和线程的对应关系有点复杂(还有1:n,n:n的对应关系)。
关于LWP与内核线程的1:1的映射关系,下面从现代的Solaris
OS(使用了NPTL线程模型)中截取的一段映射的实例来理解:


-----------------lwp#
1 / thread# 1--------------------


d22faaf5
lwp_cond_wait (8074d00, 8074ce8, 0, 0)


d1da51fc
__1cCosHSolarisFEventEdown6M_v_ (8074ce8) + 58


………………………………


-----------------lwp#
2 / thread# 2--------------------


d22faaf5
lwp_cond_wait (8073c00, 8073be8, cf4dee68, 0)


………………………………


-----------------
lwp# 26 / thread# 26 --------------------


d1a4814c
???????? ()


-----------------lwp#
27 / thread# 27--------------------


………………………………

二、RedHat
Linux中的LWP和pthread号的查看



由于当前IT行业中,Linux版本较多,而且HotSpot和JRockit认证支持的Linux供应商不同版本的Linux,所使用的线程模型、版本也各不一样,所以这里只讨论RedHat
Linux, 红帽公司从RedHat Linux 9(Linux kernel 2.4.20[glibc 2.3])版本开始采用POSIX
0.6线程模型。随后的Linux发行版中慢慢的都抛弃了LinuxThreads线程模型,转向支持基于POSIX线程(POSIX threads,又称
pthreads)的NPTL(Native POSIX Threads Library for
Linux)的新型线程模型(IBM也有一个类似的名叫NGPT项目,已于2003年中期放弃).



下面拿RedHat
Enterprise Linux 5.1(Linux kernel 2.6.18-53.e15,glibc 2.5)做下操作示例,首先用ps –ef|grep
java|grep –v grep命令获取一个java进程的pid,这里得到的javapid是2577,然后进行下面的操作:
[root@tdy218 ~]# ps -Lp 2577 cu
USER  PID   LWP  %CPU NLWP %MEM VSZ 
   RSS      TTY STAT  START  TIME   COMMAND
root   2577 2577  0.0     52    
24.2   863560 141148   ?     Sl      Oct18   0:09   java
root   2577
2578  0.0     52      24.2   863560 141148   ?     Sl      Oct18   0:00 
java
root   2577 2579  0.0     52      24.2   863560 141148   ?     Sl    
Oct18   0:00   java
.........................



当然,还可以通过调试工具GDB(具体的用法,请参阅gdb的帮助)来获得LWP号,不过不能看到CPU占用率。
本文档的目的是为了诊断java进程占用CPU异常过高故障的,使用ps命令看到的CPU%并非当前的CPU占用值,是个历史值,要想获得当前的、准确的CPU占用率,需用top命令(这里提醒大家,不要相信网上那些所谓的xxx命令详解,最好还是看帮助,man
xxx)。

然后运行一个可以造成CPU占用很高(死循环等)的java
web程序:
关键代码(好久没写代码了,很A级的一段代码):
package
tdy218.alg;
import javax.servlet.*;
import javax.servlet.http.*;
import
java.io.IOException;

public  class DeadLoop extends HttpServlet{

 
public void init(ServletConfig config) throws ServletException
   {
    
    super.init(config);
   }

   public void service(HttpServletRequest
request,HttpServletResponse response) throws IOException
   {
    
   try{
             while(true){
                  
Math.exp(Math.PI);  //求欧拉数e的π次幂.
                  }
            }
    
  catch(Exception e){
             while(true){
                
Math.exp(Math.PI);
                 }
            }
    
}
}

部署并运行.


接着执行下面的命令:
[root@tdy218 alone_domain]# top -Hp 2577 -d 1 -n 1
Tasks:  53
total,   2 running,  51 sleeping,   0 stopped,   0 zombie
Cpu(s): 39.5%us,
15.6%sy,  0.0%ni, 30.4%id, 14.2%wa,  0.1%hi,  0.3%si,  0.0%st
……………………
PID
USER     PR  NI  VIRT  RES  SHR S %CPU %MEM TIME+   UID COMMAND
2577 root 
   15   0  612m 587m 1512 S  0.0 61.5   0:28.62    0         java   
2580 root 22 0 612m 587m 1512 S 0.0 61.5 0:00.00 0 java
2581 root     18   0  612m 587m 1512 S  0.0 61.5   0:00.00    0       
java   
2582 root     18   0  612m 587m 1512 S  0.0 61.5   0:00.00    0    
    java   
……………………
2602 root     19   0  612m 587m 1512 S  0.0 61.5 
0:00.00    0         java   
2603 root    25   0  612m
587m 1512 R 95.6 61.5   4:02.32    0         java   

……………………
可以多执行几次(更准确),并将结果输出到一个文件中,可加"-b”参数.
如果还想对CPU占用进行排序,可结合sort等排序命令(看sort命令的帮助).
然后记下这个PID为2603的线程,并对该java进程做kill
-3操作:
kill -3 2577
做完上面的操作,你将得到两个重要的信息:一个是占用CPU最高的1个或多个pthread
id(即上面的PID列,其实就是LWP对应的内核线程号)和Thread Dump信息(对于WebLogic
Server来说,默认在标准输出中,如果在启动时指定了标准输出重定向到一个文件中,那么请找从该文件中找到本次kill -3操作生成的Thread
Dump的完整信息,另存到一个文本文件中,文件名自定)。

三、RedHat Linux下HotSpot 和JRockit
JVM异常CPU占用过高诊断
从上一步拿到的占用CPU很高的1个或多个内核线程号(pid)和Thread Dump信息,根据WebLogic
Server使用的JVM的供应商不同,分下面2个分析方法:
1.使用的是Sun HotSpot
JVM
需将那个(些)内核线程号(pid)转换成16进制的值,在Thread
Dump信息信息中搜索nid等于该值的线程即可,如下:
"ExecuteThread: '14' for queue:
'weblogic.kernel.Default'" daemon prio=1 tid=0x09d11df0
nid=0xa2b runnable [0x8a127000..0x8a1281a8]
        at
java.lang.StrictMath.exp(Native Method)
        at
java.lang.Math.exp(Math.java:234)
        at
tdy218.alg.DeadLoop.service(DeadLoop.java:17)
        at
javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
    
   …………………
由于JVM使用的glibc版本等原因,Sun HotSpot JVM 1.4.2 update
11(包含该版本)的threaddump信息中不包含nid,这时需要升级Sun HotSpot JVM 1.4.2 update 11的小版本即可,如:
update
12,在1.4.2这个大版中,也是从这个版本开始支持发生OutOfMemoryError故障时生成HeadDump文件的。
2.使用的是Oracle
JRockit JVM
只接拿那个(些)内核线程号(pid) 的值,在Thread Dump信息信息中搜索tid等于该值的线程即可(从 JRockit 的
70SP4RP2 和 81SP2RP1 以后的版本起,就可实现此映射,Linux下WebLogic Server自带的JRockit
R26.3就是在他们之后的版本),因为JRockit JVM的Thread Dump信息中不包含nid的值,不过JRockit
JVM提供一个更简单的tid,等于那个(些)内核线程号(pid)的值,而且是十进制的,无需进行进制转换。如下:
"ExecuteThread: '14'
for queue: 'weblogic.kernel.Default'" id=25 idx=0x32 tid=2603
prio=5 alive, in native, daemon
    at <unknown>(???.c)@0xb7fc4402
 
  at ptWaitForEvent+45(:0)@0xb7e92b31
    at
vmtWaitUntilNotSoftSuspended+70(:0)@0xb7e9e436
    at
tsCheckTransitToJava+26(:0)@0xb7e9e50a
    at
java/lang/StrictMath.exp(D)D(Native Method)
    at
java/lang/Math.exp(D)D(Math.java:234)[optimized]
    at
tdy218/alg/DeadLoop.service(Ljavax/servlet
   
/http/HttpServletRequest;Ljavax/servlet/http/HttpServletResponse;)V
   
(DeadLoop.java:17)
     ………………………

延伸阅读:
1.POSIX线程
http://www.ibm.com/developerworks/cn/linux/theme/posix_thread/
2.Linux线程模型比较Linux
Threads和NPTL
http://www.ibm.com/developerworks/cn/linux/l-threading.html
3.Linux线程实现机制分析
https://www.ibm.com/developerworks/cn/linux/kernel/l-thread/
4.O'Reilly公司出版的《Understanding
the Linux Kernel, 3rd Edition》Chapter 3. Processes中的: 3.1. Processes,
Lightweight Processes, and Threads 和 3.4. Creating Processes
posted on 2014-07-29 10:46 张金鹏 阅读(160) 评论(0)  编辑  收藏

只有注册用户登录后才能发表评论。


网站导航: