調試核心轉儲檔案
在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工件
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBHL0FWby9mZvwVZnFWbp1zczV2YvJHctM3cv1Ce-4mQuFWdFRUT3VlMahWMXFmdN52YwETejFnVHpld1cFTyJlMjR3YXRWaWdkW0FEWiFjUXxEbOhVY5JkbjxmUuJGbxMlWrlTbiRHMtlFcxMVWzkzUllnRtNWasdkY2l0VaNTO5NmcKNjYzoEWadXOHJGbahlWrlzUiZnTtxEdKdVY1N2MkNTO5xkNNh0YwIFSh9CXuNmLn1WauR2cj5CdyVmdu92Yn1Wavw1LcpDc0RHaiojIsJye.jpg)
浏覽到核心轉儲的位置,然後單擊“ 完成” 。
要在另一台計算機上打開轉儲,請使用常用工具複制轉儲檔案,然後按照我們剛才描述的方式在第二個系統上的IDDE中打開它。 為了在将轉儲複制到其他位置或另一台計算機時獲得更好的本機堆棧跟蹤,還請将Node可執行檔案複制到同一目錄中以使符号得以解析。
現在,您需要在IDDE編輯器中工作。 從新的核心檔案下面選擇“ 開始調查”以打開編輯器。
圖2.打開IDDE編輯器
大的轉儲檔案可能需要花費更多的時間來加載。
IDDE指令
可以将IDDE編輯器視為編輯器和控制台之間的混合體。 您可以像在控制台中一樣在IDDE編輯器中輸入和運作指令,但是您的進度将儲存為編輯器中的指令。
要運作指令,您必須在其前面加上
!
然後按Ctrl + Enter 。 例如,
!help
,然後按Ctrl + Enter ,輸出幫助消息,其中列出了用于轉儲的其他可用指令。 Node指令集與Java集不同,對于不同版本的Node(或Java)甚至可以有所不同,因為在更高版本的IDDE中添加了新指令。
與其他Eclipse編輯器一樣, Ctrl + Space會顯示完成建議,對于IDDE編輯器,這是指令清單。
圖3.使用Ctrl + Space打開的指令清單
最好的指令開頭是
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轉儲:
- 在指定位址顯示固定數組的元素
- 在記憶體中查找字元串
- 顯示有關單個JavaScript堆棧架構的詳細資訊
- 顯示指令清單
- 以十六進制和ASCII格式輸出一部分記憶體
- 查找具有指定屬性JavaScript對象
- 列出共享相同
JavaScript對象組Map
- 列出指定V8對象類型的堆對象
- 顯示有關JavaScript記憶體使用情況的資訊,包括五個最大的對象
- 顯示JavaScript對象的詳細資訊
- 列印與提供的對象共享相同
JavaScript對象Map
- 在堆上搜尋給定的字元串
- 在記憶體中搜尋給定的字元串
- 顯示節點資訊的概述,包括版本
- 列出所有V8對象類型
- 顯示按V8執行個體類型分類的堆使用情況
- 顯示指定堆對象的C ++層次結構
- 列印可用記憶體範圍清單
- 顯示給定線程JavaScript堆棧跟蹤
- 在指定位址顯示字元串
- 列出所有線程
array
find
, findall
, findnext
frame
help
hexdump
jsfindbyproperty
jsgroupobjects
jslistobjects
jsmeminfo
jsobject
jsobjectsmatching
jsstringsearch
locate
nodeoverview
objtype
objtypes
print
ranges
stack
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
調試核心轉儲檔案