调试核心转储文件_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以使核心文件的生成不受大小限制。

如果尚未引发异常,则需要使用系统工具(例如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工件
该图显示了选择新PD工件

浏览到核心转储的位置,然后单击“ 完成”

要在另一台计算机上打开转储,请使用常用工具复制转储文件,然后按照我们刚才描述的方式在第二个系统上的IDDE中打开它。 为了在将转储复制到其他位置或另一台计算机时获得更好的本机堆栈跟踪,还请将Node可执行文件复制到同一目录中以使符号得以解析。

现在,您需要在IDDE编辑器中工作。 从新的核心文件下面选择“ 开始调查”以打开编辑器。

图2.打开IDDE编辑器
该图显示了打开IDDE编辑器

大的转储文件可能需要花费更多的时间来加载。

IDDE命令

可以将IDDE编辑器视为编辑器和控制台之间的混合体。 您可以像在控制台中一样在IDDE编辑器中输入和运行命令,但是您的进度将保存为编辑器中的命令。

要运行命令,您必须在其前面加上! 然后按Ctrl + Enter 。 例如, !help ,然后按Ctrl + Enter ,输出帮助消息,其中列出了用于转储的其他可用命令。 Node命令集与Java集不同,对于不同版本的Node(或Java)甚至可以有所不同,因为在更高版本的IDDE中添加了新命令。

与其他Eclipse编辑器一样, Ctrl + Space会显示完成建议,对于IDDE编辑器,这是命令列表。

图3.使用Ctrl + Space打开的命令列表
该图显示了使用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命令: jsfindbypropertyjsobject来确认是这种情况。 。 jsfindbyproperty在堆中搜索所有具有提供的名称属性的对象(在此示例中为counterjsobject显示该对象的属性。

!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
在指定地址显示固定数组的元素
findfindallfindnext
在内存中查找字符串
frame
显示有关单个JavaScript堆栈框架的详细信息
help
显示命令列表
hexdump
以十六进制和ASCII格式输出一部分内存
jsfindbyproperty
查找具有指定属性JavaScript对象
jsgroupobjects
列出共享相同MapJavaScript对象组
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有任何疑问,或者想报告该工具的错误或问题,请发送电子邮件至javatool@uk.ibm.com


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

调试核心转储文件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值