Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
CLI for inspecting the heap of a node application
JavaScript
Branch: master

Fetching latest commit…

Cannot retrieve the latest commit at this time

Failed to load latest commit information.
bin
lib
.gitignore
AUTHORS
README.md
package.json

README.md

nodeheap

CLI for inspecting the heap of a node application

Installation

npm install https://github.com/seth4618/nodeheap

Usage

The program undertest needs to run a tcpserver which you get from:

var heapserver = require('nodeheap/lib/heapserver');    // include basic code
heapserver(port);               // start heapserver on port 'port'

For example, in my code I define a runtime argument profileMemOn and profilePort and do the following:

if (profileMemOn) {
    HeapServer = (/** @type {function (number, boolean=):?} */require('nodeheap/lib/heapserver'));
    HeapServer(profilePort);
}

Then to see what is going on run the command:

nodeheap --port <port>

on the command line will connect to the program undertest. The following commands are available:

  • login: gets things started
  • quit: will exit
  • help: print a set of commands

  • base: Will set the base profile to the last profile used. Or, if none has been used will create a profile.

  • comp: Will compare the current heap profile with whatever was set as the base profile.
  • info <type> <name>: show information on all objects of type 'type' with name 'name'. A '*' in either will include everything. I.e., info Object * will show all objects, while info Object Foo will only show those objects with the name Foo.
  • chain <id>: will show the retainer chain for object with id, <id>.
  • value <id> <depth> <hidden>: will show the value of object with id <id> to a depth of <depth>. <depth> is optional, if not supplied will do <depth> = 2. If 'hidden' is specified will also include hidden members.
  • inspect <id> <path>: will show the value of the object <id>.<path>

Example

You can test things out by running nodeheap with the --test switch, specify a port and nodeheap will run on itself. For example, here is a sample session:

> nodeheap --test 8877
Welcome to the heap probe utility.
You are testing nodeheap on itself!
Will probe application running on localhost:8877

use "login" command when you are ready to connect to the application
            #
        # enter the 'login' command to connect to the application
        #
notlogged in> login

            #
        # enter the 'base' command to get a snapshot you can refer to
        #
> base

            #
        # ask for info on all things that are of type 'Object' with name 'HeapConnection'
        #
> info Object HeapConnection
{ data: 
   [ { name: 'HeapConnection',
       type: 'Object',
       size: 24,
            #
        # the id listed here can be used to get the actual value of this object
        #
       id: 241,
       retainers: [Object] },
     { name: 'HeapConnection',
       type: 'Object',
       size: 104,
       id: 25891,
       retainers: [Object] } ],
  command: 'info' }
            #
        # show the value of the last of the objects shown above to depth 1, no hidden fields
        #
> value 25891 1
showing value of 25891:HeapConnection:Object:104 ret:17
Value of Object:HeapConnection size:104 retainers:17
String: [object Object]
Value:
{ server: 
   { name: 'test',
     port: 8877,
     verbose: false,
     connClass: [Object],
     _events: [Object],
     server: [Object] },
  socket: 
   { _handle: [Object],
     _pendingWriteReqs: 0,
     _flags: 0,
     _connectQueueSize: 0,
     destroyed: false,
     errorEmitted: false,
     bytesRead: 80,
     bytesWritten: 805,
     allowHalfOpen: false,
     writable: true,
     readable: true,
     server: [Object],
     _events: [Object] },
  buffer: '',
  verbose: false,
  _events: { data: [Function], malformed: [Function], connect: [Function] },
  base: 
   { type: 'Full',
     root: [Object],
     nodesCount: 15697,
     uid: 1,
     title: 'org.nodejs.profiles.heap.user-initiated.1',
     getNodeById: [Function: getNodeById],
     getNode: [Function: getNode],
     delete: [Function: delete],
     serialize: [Function: serialize] } }
-------------
            #
        # inspect the 'base' field of the above object
        #
> inspect 25891 base
showing value of 25891:HeapConnection:Object:104 ret:17
Value of Object:HeapConnection size:104 retainers:17
String: [object Object]
Partial path upto: base
Value:
{ type: 'Full',
  root: 
   { size: 0,
     name: '',
     id: 1,
     ptr: 1965359232,
     dominatorNode: 
      { size: 0,
        name: '',
        id: 1,
        ptr: 1965359232,
        dominatorNode: [Object],
        type: 'Object',
        retainersCount: 0,
        childrenCount: 2,
        getChild: [Function: getChild],
        retainedSize: [Function: retainedSize],
        getRetainer: [Function: getRetainer],
        getHeapValue: [Function: getHeapValue],
        getHeapValueSafe: [Function: getHeapValueSafe] },
     type: 'Object',
     retainersCount: 0,
     childrenCount: 2,
     getChild: [Function: getChild],
     retainedSize: [Function: retainedSize],
     getRetainer: [Function: getRetainer],
     getHeapValue: [Function: getHeapValue],
     getHeapValueSafe: [Function: getHeapValueSafe] },
  nodesCount: 15697,
  uid: 1,
  title: 'org.nodejs.profiles.heap.user-initiated.1',
  getNodeById: [Function: getNodeById],
  getNode: [Function: getNode],
  delete: [Function: delete],
  serialize: [Function: serialize] }-------------
            #
        # inspect the 'object.base.title' 
        #
> inspect 25891 base.title
showing value of 25891:HeapConnection:Object:104 ret:17
Value of Object:HeapConnection size:104 retainers:17
String: [object Object]
Partial path upto: base.title
Value:
'org.nodejs.profiles.heap.user-initiated.1'-------------
            #
        # compare the heap now to the snapshot set when we executed the 'base' command
        # each line shows the change in the number of type/name objects in the heap.  That is, 
        # There are 68 more Array's with the name '(map descriptor content)' and
        # 1 fewer object of type 'Code' with the name: 'symToFamily'.
        #
> comp
{ data: 
   [ { type: 'Array', name: '(map descriptor content)', val: 68 },
     { type: 'Hidden', name: 'system / Map', val: 62 },
     { type: 'Array', name: '(map descriptors)', val: 53 },
     { type: 'Hidden', name: 'system / Foreign', val: 43 },
     { type: 'Array', name: '', val: 26 },
     { type: 'Object', name: 'Object', val: 19 },
     { type: 'Array', name: '(code deopt data)', val: 17 },
     { type: 'Hidden', name: 'system / AccessorInfo', val: 17 },
     { type: 'Hidden',
       name: 'system / FunctionTemplateInfo',
       val: 12 },
     { type: 'Array', name: '(object elements)', val: 9 },
     { type: 'Hidden', name: 'system / CallHandlerInfo', val: 9 },
     { type: 'Object', name: 'Array', val: 7 },
     { type: 'HeapNumber', name: 'number', val: 5 },
     { type: 'Hidden', name: 'system / ObjectTemplateInfo', val: 3 },
     { type: 'RegExp', name: '\'', val: 1 },
     { type: 'Object', name: 'getRetainer', val: 1 },
     { type: 'Closure', name: '', val: 1 },
     { type: 'Hidden', name: 'system / JSGlobalPropertyCell', val: 1 },
     { type: 'Object', name: 'getHeapValueSafe', val: 1 },
     { type: 'Code', name: 'retainedSize', val: 1 },
     { type: 'RegExp', name: '\\\\\\\'', val: 1 },
     { type: 'RegExp', name: '^"([a-zA-Z_][a-zA-Z_0-9]*)"$', val: 1 },
     { type: 'Closure', name: 'getChild', val: 1 },
     { type: 'RegExp', name: 'all', val: 1 },
     { type: 'Object', name: 'delete', val: 1 },
     { type: 'Closure', name: 'getNode', val: 1 },
     { type: 'Closure', name: 'getNodeById', val: 1 },
     { type: 'Object', name: 'getNodeById', val: 1 },
     { type: 'Object', name: 'getHeapValue', val: 1 },
     { type: 'Code', name: 'getChild', val: 1 },
     { type: 'Object', name: 'getChild', val: 1 },
     { type: 'Closure', name: 'retainedSize', val: 1 },
     { type: 'Object', name: 'getNode', val: 1 },
     { type: 'Closure', name: 'getHeapValue', val: 1 },
     { type: 'RegExp', name: '^\\d+$', val: 1 },
     { type: 'Code', name: 'getHeapValue', val: 1 },
     { type: 'Code', name: 'getNodeById', val: 1 },
     { type: 'Closure', name: 'delete', val: 1 },
     { type: 'Code', name: 'serialize', val: 1 },
     { type: 'RegExp', name: '\\\\n', val: 1 },
     { type: 'Closure', name: 'getRetainer', val: 1 },
     { type: 'Code', name: 'getRetainer', val: 1 },
     { type: 'RegExp', name: 'string', val: 1 },
     { type: 'RegExp', name: '^"|"$', val: 1 },
     { type: 'Code', name: 'getHeapValueSafe', val: 1 },
     { type: 'Code', name: 'delete', val: 1 },
     { type: 'RegExp', name: '[0-9]+', val: 1 },
     { type: 'Object', name: 'serialize', val: 1 },
     { type: 'Code', name: 'getNode', val: 1 },
     { type: 'Object', name: 'retainedSize', val: 1 },
     { type: 'Closure', name: 'serialize', val: 1 },
     { type: 'RegExp', name: '\\\\"', val: 1 },
     { type: 'Closure', name: 'getHeapValueSafe', val: 1 },
     { type: 'Code', name: 'familyToSym', val: -1 },
     { type: 'Code', name: 'realpathSync', val: -1 },
     { type: 'Code', name: 'trim', val: -1 },
     { type: 'Code', name: '$assert', val: -1 },
     { type: 'Object', name: 'Timer', val: -1 },
     { type: 'Code', name: 'symToFamily', val: -1 },
     { type: 'Object', name: 'Date', val: -1 },
     { type: 'Array', name: '(object properties)', val: -2 },
     { type: 'Code', name: 'f', val: -2 },
     { type: 'Array', name: '(code relocation info)', val: -26 },
     { type: 'Array', name: '(function scope info)', val: -29 },
     { type: '', name: 'String', val: -60 },
     { type: 'Code', name: '', val: -81 } ],
  command: 'comp' }
            #
        # all done.  use the 'help' command for a list of commands.
        #
> quit
Something went wrong with that request. Please try again.