npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

nodeheap

v0.0.4

Published

CLI to probe the heap of a node application, help find memory leaks, etc.

Downloads

7

Readme

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