天天看點

調試核心轉儲檔案_IBM SDK for Node.js的核心轉儲調試

調試核心轉儲檔案

在Node.js開發中,核心轉儲分析可以幫助調試程式崩潰和記憶體洩漏。 IBM SDK for Node.js通過IBM監視和診斷工具-互動式診斷資料資料總管 (IDDE)為Node.js應用程式提供了一種新的核心轉儲分析和調試方法。 IDDE是Eclipse附加元件,可以免費獲得,它可以從分布有Node.js的IBM SDK的所有平台(除Mac OS X之外)支援核心轉儲。 您可以從一台計算機上進行核心轉儲,然後在另一台計算機上的IDDE中打開它-甚至是運作不同(受支援)作業系統的計算機。

您可以從Eclipse Marketplace安裝IDDE或使用更新站點 。 繼續閱讀以了解如何在開發Node.js應用程式時将IDDE用于程式崩潰和記憶體洩漏。

生成核心轉儲

生成核心轉儲的方法因系統而異。 Joyent(Node.js的企業管理者)建議使用

--abort-on-uncaught-exception

标志運作所有生産Node.js系統。 在UNIX系統上,還需要設定

ulimit -c unlimited

以使核心檔案的生成不受大小限制。

擴充IDDE支援

IDDE支援IBM Java核心轉儲的探索和調試已有數年。 随着2013年IBM SDK for Node.js的釋出,Node.js支援已在1.2版中添加到IDDE中。 IDDE 1.2.2還添加了對IBM SDK for Node.js版本1.2.x(相當于Node 0.12.x)的支援。

如果尚未引發異常,則需要使用系統工具(例如Linux上的

gcore

或AIX上的

gencore

來生成核心檔案,或者-如果您樂意殺死該程序,則使用

kill -11

。 在Windows 7和更高版本上,可以使用任務管理器生成核心轉儲:按Ctrl + Alt + Delete并選擇啟動任務管理器 。 在“程序”頁籤中,右鍵單擊Node.js程序,然後選擇“ 建立轉儲檔案” 。 也可以使用Windows的免費ProcDump實用程式。

調試崩潰

為了産生程式崩潰,我們将使用Test.js腳本。 這個簡單的腳本循環執行五次,然後引發錯誤。

清單1. Test.js
function main() {
  var inputObject = {
    input: ["one", "two", "three", "fifteen", "one hundred"],
    counter:0,
  };

  for(; inputObject.counter< inputObject.input.length; inputObject.counter++) {
    if (inputObject.input[inputObject.counter].length > 8) {
      throw "Input String Too Big";
    }
  }
}

main();
           

您可以像這樣在Linux上運作test.js:

$ cd node-v0.12.4-linux-x64/bin/
$ ulimit -c unlimited
$ ./node --abort-on-uncaught-exception ../../test.js
Uncaught Input String Too Big

FROM
main (/home/sian/test.js:11:7)
Object.<anonymous> (/home/sian/test.js:16:1)
Module._compile (module.js:460:26)
Object.Module._extensions..js (module.js:478:10)
Module.load (module.js:355:32)
Function.Module._load (module.js:310:12)
Function.Module.runMain (module.js:501:10)
startup (node.js:129:16)
node.js:814:3
Illegal instruction (core dumped)
           

在IDDE中打開核心轉儲

如果在核心轉儲所在的同一台計算機上安裝并運作了IDDE,則可以直接從其磁盤位置打開核心轉儲。 右鍵單擊PD Navigator視圖(PD代表問題确定),然後選擇New PD Artifact 。

圖1.選擇新的PD工件
調試核心轉儲檔案_IBM SDK for Node.js的核心轉儲調試

浏覽到核心轉儲的位置,然後單擊“ 完成” 。

要在另一台計算機上打開轉儲,請使用常用工具複制轉儲檔案,然後按照我們剛才描述的方式在第二個系統上的IDDE中打開它。 為了在将轉儲複制到其他位置或另一台計算機時獲得更好的本機堆棧跟蹤,還請将Node可執行檔案複制到同一目錄中以使符号得以解析。

現在,您需要在IDDE編輯器中工作。 從新的核心檔案下面選擇“ 開始調查”以打開編輯器。

圖2.打開IDDE編輯器
調試核心轉儲檔案_IBM SDK for Node.js的核心轉儲調試

大的轉儲檔案可能需要花費更多的時間來加載。

IDDE指令

可以将IDDE編輯器視為編輯器和控制台之間的混合體。 您可以像在控制台中一樣在IDDE編輯器中輸入和運作指令,但是您的進度将儲存為編輯器中的指令。

要運作指令,您必須在其前面加上

!

然後按Ctrl + Enter 。 例如,

!help

,然後按Ctrl + Enter ,輸出幫助消息,其中列出了用于轉儲的其他可用指令。 Node指令集與Java集不同,對于不同版本的Node(或Java)甚至可以有所不同,因為在更高版本的IDDE中添加了新指令。

與其他Eclipse編輯器一樣, Ctrl + Space會顯示完成建議,對于IDDE編輯器,這是指令清單。

圖3.使用Ctrl + Space打開的指令清單
調試核心轉儲檔案_IBM SDK for Node.js的核心轉儲調試

最好的指令開頭是

nodeoverview

,它提供了您正在運作的Node版本,依賴項等的基本摘要。

!nodeoverview {

Node Property           Value                                                        
----------------------  -------------------------------------------------------------
Node version            0.12.4                                                       
Path to executable      /home/sian/node-v0.12.4-linux-x64/bin/node                   
Architecture            x64                                                          
Platform                linux                                                        
Command Line Arguments  /home/sian/node-v0.12.4-linux-x64/bin/node /home/sian/test.js
Execution Arguments     --abort-on-uncaught-exception                                
Process ID              5643                                                        

Dependency   Version   
-----------  ----------
http_parser  2.3       
node         0.12.4    
v8           3.28.71.19          2.2    

[...]
           

調查問題

您可以從前面的控制台輸出中看到程式由于未捕獲的異常而崩潰,是以這裡要做的第一件事是檢視堆棧跟蹤。 運作

threads

指令以查找線程ID。

!threads {

Thread ID: 0x74c9 (29897) IP: 0x0000000000eb112d
    !stack 29897

}
           

隻有一個線程在運作,是以它必須是JavaScript線程。

嘗試對線程執行

stack

指令。 該指令的快捷方式包含在

threads

指令的輸出中,是以您可以将光标放在包含

!stack 29897

的行的末尾,然後按Ctrl + Space 。 這是輸出(為了提高可讀性;我們删除了arguments列并截斷了一些行):

!stack 29897 {

Instruction Pointer  Frame Address       Location / Frame Type                                                                                                                                     
-------------------  ------------------  ------------------------------------------------------------------------------------
 0x0000000000eb112d  0x00007FFF0A81F960  node::_ZN2v84base2OS11GetUserTimeEPjS2_+0x9d                                              
 0x0000000000a890c1  0x00007FFF0A81FAC0  node::_ZN2v88internal7Isolate29CaptureAndSetSimpleStackTraceENS0_6HandleINS0_8JSO...                                                 
 0x0000000000b63c9d  0x00007FFF0A81FAF0  node::_ZN2v88internal25Runtime_ThrowNotDateErrorEiPPNS0_6ObjectEPNS0_7IsolateE+0xdd
 0x00000E7CAA2A8E32  0x00007FFF0A81FB40  main [/home/sian/test.js]                                                                                                                                    
                                         !jsobject 0x00001519ED09B451                                                                                                                                       
 0x00000E7CAA2A8B34  0x00007FFF0A81FB78  <anonymous> [/home/sian/test.js]                                                                                    
                                         !jsobject 0x00001519ED09B341                                                                                                    
 0x00000E7CAA224AC6  0x00007FFF0A81FBE0  INTERNAL FRAME                                                                                                                                                     
 0x00000E7CAA2A7D26  0x00007FFF0A81FC58  Module._compile [module.js]                                                                                                                 
                                         !jsobject 0x00000DA39E6185F9                                                                                            
 0x00000E7CAA2A220C  0x00007FFF0A81FCA0  Module._extensions..js [module.js]                                                                                  
                                         !jsobject 0x00000DA39E618691                                                                                            
 0x00000E7CAA29E940  0x00007FFF0A81FCE8  Module.load [module.js]                                                                                                  
                                         !jsobject 0x00000DA39E618569                                                                                                                                      
 0x00000E7CAA295565  0x00007FFF0A81FD70  Module._load [module.js]           
                                         !jsobject 0x00000DA39E6184D9           
 0x00000E7CAA294F24  0x00007FFF0A81FDB8  Module.runMain [module.js]                                                                          
                                         !jsobject 0x00000DA39E618721                                                                                                       
 0x00000E7CAA26B31F  0x00007FFF0A81FE28  startup [node.js]                                                    
                                         !jsobject 0x0000079578AC8A61
 0x00000E7CAA269D10  0x00007FFF0A81FE58  <anonymous> [node.js]       
                                         !jsobject 0x0000079578A6EF49                                                                                                                                      
 0x00000E7CAA21EF40  0x00007FFF0A81FE98  INTERNAL FRAME                                                                                                                                                     
 0x00000E7CAA21DE90  0x00007FFF0A81FF20  ENTRY FRAME                                                                                                                                                        
 0x00000E7CAA21DE90  0x00007FFF0A81FF20  ENTRY FRAME                                                                                                                                                        
 0x0000000000914E28  0x00007FFF0A81FFF0  NONE FRAME                                                                                                                                                         
 0x0000000000813bda  0x00007FFF0A820060  node::_ZN2v88Function4CallENS_6HandleINS_5ValueEEEiPS3_+0xba                                                                                                      
 0x0000000000c9d40f  0x00007FFF0A820190  node::_ZN4node15LoadEnvironmentEPNS_11EnvironmentE+0x1df                                                                                                          
 0x0000000000c9d67f  0x00007FFF0A8202E0  node::_ZN4node15LoadEnvironmentEPNS_11EnvironmentE+0x44f                                                                                                          
 0x0000003d0fa1ed5d  0x0000000000000000  node::_fini+0x3d0eb6c8c5                                                                                                                                          

}
           

您可以看到崩潰是在

main

方法中發生的。 傳回代碼以檢視可能發生的情況,您無需離開IDDE。 如果運作前面的輸出中以粗體顯示的指令,則IDDE将向您顯示源。

!jsobject 0x00001519ED09B451 {

Object has fast properties
Number of descriptors : 5

Name       Value               More Information               
---------  ------------------  -------------------------------
length     0x0000079578A0FE19  <EXECUTABLE_ACCESSOR_INFO_TYPE>
name       0x0000079578A0FE51  <EXECUTABLE_ACCESSOR_INFO_TYPE>
arguments  0x0000079578A0FE89  <EXECUTABLE_ACCESSOR_INFO_TYPE>
caller     0x0000079578A0FEC1  <EXECUTABLE_ACCESSOR_INFO_TYPE>
prototype  0x0000079578A0FEF9  <EXECUTABLE_ACCESSOR_INFO_TYPE>

Object is a function

Name: main

Source:

() {
  var inputObject = {
    input: ["one", "two", "three", "fifteen", "one hundred"],
    counter:0,
  };

  for(; inputObject.counter< inputObject.input.length; inputObject.counter++) {
    if (inputObject.input[inputObject.counter].length > 8) {
      throw "Input String Too Big";
    }
  }
}
}
           

注意:此功能對于确認您認為正在運作的代碼是否确實在運作也很有用。

從代碼看來,

mainObject.counter

必須達到4,該長度指向長度超過8的字元串

"one hundred"

。您可以通過使用其他兩個IDDE指令:

jsfindbyproperty

jsobject

來确認是這種情況。 。

jsfindbyproperty

在堆中搜尋所有具有提供的名稱屬性的對象(在此示例中為

counter

jsobject

顯示該對象的屬性。

!jsfindbyproperty counter {

!jsobject 0x00001519ED09B539
!jsobject 0x00001519ED09B689

}


!jsobject 0x00001519ED09B689 {

Object has fast properties
Number of descriptors : 2

Name     Value               More Information                             
-------  ------------------  ---------------------------------------------
input    0x00001519ED09B6C1  <JS Array[5]> :- !jsobject 0x00001519ed09b6c1
counter  0x0000000400000000  SMI = 4                                      

}
           

jsfindbyproperty

生成的十六進制數字(例如

0x00003CF51F09B441

)向您顯示該指令找到的對象的記憶體位址。 您可以針對這些十六進制位址之一運作

jsobject

指令,并且如果JavaScript對象位于該位址,則該指令将輸出有關該對象屬性的資訊。 在這種情況下,我們可以看到該對象的

counter

已達到4。

現在,使用前面輸出中的shortcut指令檢視

input

數組。

!jsobject 0x00001519ed09b6c1 {

Array at !hexdump 0x00001519ED09B4E1
Array len = 5

0 : 0x00000CEAAC1A3679, one
1 : 0x00000CEAAC1A3699, two
2 : 0x00000CEAAC1A36B9, three
3 : 0x00000CEAAC1A36D9, fifteen
4 : 0x00000CEAAC1A36F9, one hundred

}
           

您可以在test.js代碼中看到未能通過測試并導緻引發異常的數組元素。

查找記憶體洩漏

記憶體洩漏可能是任何程式中的常見問題。 IDDE有幾個指令可幫助跟蹤哪些對象占用了記憶體。 在此示例中,我們從一個我們認為正在洩漏記憶體的Node.js應用程式中提取核心轉儲開始。

跟蹤洩漏的一種方法是擷取兩個或多個轉儲,并且它們之間的時間間隔很長,并比較兩個轉儲之間某些指令的輸出。

jsmeminfo

指令可以幫助立即顯示一個非常大的對象是否占用了大量空間,如本例所示。

!jsmeminfo {

Memory allocator, used: 1423 MB, available: 0 MB
Total Heap Objects: 29497

Largest 5 heap objects  Type               Size (bytes)  More information          
----------------------  -----------------  ------------  --------------------------
0x0000000088a6d319      JS_OBJECT_TYPE          1311125  !jsobject 0x0000000088a6d319
0x0000000088aac6d9      FIXED_ARRAY_TYPE          98360  !array 0x000003ff88aac6d9
0x000003ff8abe31b9      ASCII_STRING_TYPE         48176  !string 0x000003ff8abe31b9
0x000003ff8ab34f09      ASCII_STRING_TYPE         48104  !string 0x000003ff8ab34f09
0x000003ff8ab04101      ASCII_STRING_TYPE         40936  !string 0x000003ff8ab04101
           

與在調試崩潰部分中一樣,對該對象運作

jsobject

指令将使您能夠将其與程式中的對象相關聯并解決問題。

對于另一種類型的記憶體問題,即程式正在建立許多對象而不處理它們,

jsgroupobjects

将相同類型的對象分組,

jsgroupobjects

您顯示程式中有多少對象。

jsgroupobjects

還可以通過顯示對象的構造函數來幫助确定Node.js緩沖區的使用位置。 (Node中的緩沖區是一種在堆外部配置設定記憶體的方法。)在此示例中,

Buffer

是最經常出現的對象:

!jsgroupobjects {

Representative Object Address  Object Type    Num Objects Constructor  Num Properties  Properties                                                                      
-----------------------------  -------------  ----------  -----------  --------------  ---------------
!jsobject 0x000003ffec004101   JS_OBJECT_TYPE       2572      Buffer         2        length, parent
...
           

您可以通過辨別緩沖區配置設定的外部數組的位置來列印出IDDE中緩沖區的内容(在以下輸出中以粗體顯示)。

print 0x000003ffec004101 {

Object at 0x000003FFEC004101 is JSObject

Class hierarchy :-

|-JSObject
|  |- kElementsOffset 0x10 (EXTERNAL_UINT8_ARRAY_TYPE, !print 0x000003FFEC004159)
|  |- kPropertiesOffset 0x8 (FIXED_ARRAY_TYPE, !print 0x000003FF92A04111)
| |-JSReceiver
| | |-HeapObject
| | |  |- kMapOffset 0x0 (MAP_TYPE, !print 0x000003FF8BE1F6E9)
| | | |-Object
...
           

擷取

kElementsOffset

的位址,并輸入

array

指令。

!array 0x000003FFEC004159 {

Array type : EXTERNAL_UINT8_ARRAY_TYPE
Len : 10
0 0x48 H
1 0x65 e
2 0x6c l
3 0x6c l
4 0x6f o
5 0x20 
6 0x6e n
7 0x6f o
8 0x64 d
9 0x65 e
..
           

objtypes

指令對于記憶體問題也很有用。 它顯示了V8堆對象類型在記憶體中的計數和大小。

完整指令參考

這是IDDE的完整指令參考。 此處以斜體顯示的指令可用于任何核心轉儲。 所有其他特定于Node.js轉儲:

array

在指定位址顯示固定數組的元素

find

findall

findnext

在記憶體中查找字元串

frame

顯示有關單個JavaScript堆棧架構的詳細資訊

help

顯示指令清單

hexdump

以十六進制和ASCII格式輸出一部分記憶體

jsfindbyproperty

查找具有指定屬性JavaScript對象

jsgroupobjects

列出共享相同

Map

JavaScript對象組

jslistobjects

列出指定V8對象類型的堆對象

jsmeminfo

顯示有關JavaScript記憶體使用情況的資訊,包括五個最大的對象

jsobject

顯示JavaScript對象的詳細資訊

jsobjectsmatching

列印與提供的對象共享相同

Map

JavaScript對象

jsstringsearch

在堆上搜尋給定的字元串

locate

在記憶體中搜尋給定的字元串

nodeoverview

顯示節點資訊的概述,包括版本

objtype

列出所有V8對象類型

objtypes

顯示按V8執行個體類型分類的堆使用情況

print

顯示指定堆對象的C ++層次結構

ranges

列印可用記憶體範圍清單

stack

顯示給定線程JavaScript堆棧跟蹤

string

在指定位址顯示字元串

threads

列出所有線程

結論

在本教程中,您學習了如何生成Node.js核心轉儲,如何在IDDE中打開轉儲,在IDDE編輯器中輸入并運作指令,以及擷取可用于轉儲的所有指令的清單。 而且,您已經了解了哪些IDDE指令可以最好地幫助您找到程式崩潰和記憶體洩漏的根本原因。

如果您對使用IDDE有任何疑問,或者想報告該工具的錯誤或問題,請發送電子郵件至[email protected] 。

翻譯自: https://www.ibm.com/developerworks/web/library/wa-ibm-node-enterprise-dump-debug-sdk-nodejs-trs/index.html

調試核心轉儲檔案