細(xì)心!用心!耐心!

          吾非文人,乃市井一俗人也,讀百卷書,跨江河千里,故申城一游; 一兩滴辛酸,三四年學(xué)業(yè),五六點(diǎn)粗墨,七八筆買賣,九十道人情。

          BlogJava 聯(lián)系 聚合 管理
            1 Posts :: 196 Stories :: 10 Comments :: 0 Trackbacks
          之前看過(guò)一篇很不錯(cuò)文檔(WLS的異常高CPU占用率分析診斷),原作英文版的,有幸看到,遺憾的是沒保存,不過(guò)中文版翻譯的也不錯(cuò),在之前的dev2dev和OTN上都有那篇文檔的中文版

          原文對(duì)5種常見的操作系統(tǒng)下WLS的異常高CPU占用率分析都有,SUN-Solaris、HP-UX、IBM-AIX、MS-Windows上的都比較詳細(xì),唯獨(dú)沒看明白Linux平臺(tái)上的分析,而且現(xiàn)在看來(lái),那篇文章中關(guān)于查找占用CPU過(guò)高的內(nèi)核進(jìn)程號(hào)的地方一筆帶過(guò),周六、周末在家又認(rèn)真的看了看Linux平臺(tái)下的top和ps這兩個(gè)常用命令的幫助,最終得已清晰,這里又加以補(bǔ)充,并作文檔一篇跟大家共享,歡迎賜教。

          一、進(jìn)程、線程和輕量級(jí)進(jìn)程(Lightweight,簡(jiǎn)稱LWP)簡(jiǎn)述

          進(jìn)程是資源管理的最小單位,而線程又是程序執(zhí)行的最小單位,一個(gè)進(jìn)程至少需要一個(gè)線程作為它的指令執(zhí)行體,進(jìn)程管理著資源(比如CPU時(shí)間片、虛擬內(nèi)存文件句柄、信號(hào)處理器等),線程可以共享這些資源。輕量級(jí)進(jìn)程(LWP)是一種由內(nèi)核支持的用戶線程。


          每一個(gè)進(jìn)程有一個(gè)或多個(gè)LWP,而每個(gè)LWP都與一個(gè)特定的內(nèi)核線程關(guān)聯(lián)(這種線程模型就是LinuxThreads和NPTL(符合POSIX)共同所有的1:1[一對(duì)一]的模型),不過(guò)NPTL線程模型中,進(jìn)程和線程的對(duì)應(yīng)關(guān)系有點(diǎn)復(fù)雜(還有1:n,n:n的對(duì)應(yīng)關(guān)系)。
          關(guān)于LWP與內(nèi)核線程的1:1的映射關(guān)系,下面從現(xiàn)代的Solaris
          OS(使用了NPTL線程模型)中截取的一段映射的實(shí)例來(lái)理解:


          -----------------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號(hào)的查看



          由于當(dāng)前IT行業(yè)中,Linux版本較多,而且HotSpot和JRockit認(rèn)證支持的Linux供應(yīng)商不同版本的Linux,所使用的線程模型、版本也各不一樣,所以這里只討論RedHat
          Linux, 紅帽公司從RedHat Linux 9(Linux kernel 2.4.20[glibc 2.3])版本開始采用POSIX
          0.6線程模型。隨后的Linux發(fā)行版中慢慢的都拋棄了LinuxThreads線程模型,轉(zhuǎn)向支持基于POSIX線程(POSIX threads,又稱
          pthreads)的NPTL(Native POSIX Threads Library for
          Linux)的新型線程模型(IBM也有一個(gè)類似的名叫NGPT項(xiàng)目,已于2003年中期放棄).



          下面拿RedHat
          Enterprise Linux 5.1(Linux kernel 2.6.18-53.e15,glibc 2.5)做下操作示例,首先用ps –ef|grep
          java|grep –v grep命令獲取一個(gè)java進(jìn)程的pid,這里得到的javapid是2577,然后進(jìn)行下面的操作:
          [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
          .........................



          當(dāng)然,還可以通過(guò)調(diào)試工具GDB(具體的用法,請(qǐng)參閱gdb的幫助)來(lái)獲得LWP號(hào),不過(guò)不能看到CPU占用率。
          本文檔的目的是為了診斷java進(jìn)程占用CPU異常過(guò)高故障的,使用ps命令看到的CPU%并非當(dāng)前的CPU占用值,是個(gè)歷史值,要想獲得當(dāng)前的、準(zhǔn)確的CPU占用率,需用top命令(這里提醒大家,不要相信網(wǎng)上那些所謂的xxx命令詳解,最好還是看幫助,man
          xxx)。

          然后運(yùn)行一個(gè)可以造成CPU占用很高(死循環(huán)等)的java
          web程序:
          關(guān)鍵代碼(好久沒寫代碼了,很A級(jí)的一段代碼):
          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);  //求歐拉數(shù)e的π次冪.
                            }
                      }
              
            catch(Exception e){
                       while(true){
                          
          Math.exp(Math.PI);
                           }
                      }
              
          }
          }

          部署并運(yùn)行.


          接著執(zhí)行下面的命令:
          [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   

          ……………………
          可以多執(zhí)行幾次(更準(zhǔn)確),并將結(jié)果輸出到一個(gè)文件中,可加"-b”參數(shù).
          如果還想對(duì)CPU占用進(jìn)行排序,可結(jié)合sort等排序命令(看sort命令的幫助).
          然后記下這個(gè)PID為2603的線程,并對(duì)該java進(jìn)程做kill
          -3操作:
          kill -3 2577
          做完上面的操作,你將得到兩個(gè)重要的信息:一個(gè)是占用CPU最高的1個(gè)或多個(gè)pthread
          id(即上面的PID列,其實(shí)就是LWP對(duì)應(yīng)的內(nèi)核線程號(hào))和Thread Dump信息(對(duì)于WebLogic
          Server來(lái)說(shuō),默認(rèn)在標(biāo)準(zhǔn)輸出中,如果在啟動(dòng)時(shí)指定了標(biāo)準(zhǔn)輸出重定向到一個(gè)文件中,那么請(qǐng)找從該文件中找到本次kill -3操作生成的Thread
          Dump的完整信息,另存到一個(gè)文本文件中,文件名自定)。

          三、RedHat Linux下HotSpot 和JRockit
          JVM異常CPU占用過(guò)高診斷
          從上一步拿到的占用CPU很高的1個(gè)或多個(gè)內(nèi)核線程號(hào)(pid)和Thread Dump信息,根據(jù)WebLogic
          Server使用的JVM的供應(yīng)商不同,分下面2個(gè)分析方法:
          1.使用的是Sun HotSpot
          JVM
          需將那個(gè)(些)內(nèi)核線程號(hào)(pid)轉(zhuǎn)換成16進(jìn)制的值,在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,這時(shí)需要升級(jí)Sun HotSpot JVM 1.4.2 update 11的小版本即可,如:
          update
          12,在1.4.2這個(gè)大版中,也是從這個(gè)版本開始支持發(fā)生OutOfMemoryError故障時(shí)生成HeadDump文件的。
          2.使用的是Oracle
          JRockit JVM
          只接拿那個(gè)(些)內(nèi)核線程號(hào)(pid) 的值,在Thread Dump信息信息中搜索tid等于該值的線程即可(從 JRockit 的
          70SP4RP2 和 81SP2RP1 以后的版本起,就可實(shí)現(xiàn)此映射,Linux下WebLogic Server自帶的JRockit
          R26.3就是在他們之后的版本),因?yàn)镴Rockit JVM的Thread Dump信息中不包含nid的值,不過(guò)JRockit
          JVM提供一個(gè)更簡(jiǎn)單的tid,等于那個(gè)(些)內(nèi)核線程號(hào)(pid)的值,而且是十進(jìn)制的,無(wú)需進(jìn)行進(jìn)制轉(zhuǎn)換。如下:
          "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線程實(shí)現(xiàn)機(jī)制分析
          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 張金鵬 閱讀(169) 評(píng)論(0)  編輯  收藏

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 民和| 咸阳市| 丰镇市| 承德市| 额尔古纳市| 基隆市| 蓝田县| 游戏| 巴塘县| 汾阳市| 凯里市| 太原市| 汉川市| 玉树县| 东宁县| 惠安县| 凯里市| 且末县| 巴林左旗| 德兴市| 东明县| 峡江县| 彭水| 大姚县| 恩平市| 信宜市| 巨鹿县| 西畴县| 苍溪县| 定南县| 毕节市| 蕲春县| 阳原县| 肥城市| 班戈县| 丽水市| 江陵县| 濮阳县| 西平县| 天等县| 紫阳县|