The Nodesource Blog

Request Garbage Collection for Node.js Processes with N|Solid

Garbage collection is one of those deep, mystical subjects that JavaScript developers generally don't have to worry about. It just happens, under the covers, and life is good.

If you're monitoring your applications with a tool like NodeSource N|Solid, you can generally notice when garbage collections occur, by watching the various memory graphs shown in the N|Solid Console. When the graph shows that memory usage decreased, garbage collection has likely occurred.

But have you ever wanted to request garbage collection to occur? The reasons you might want to include:

  • Getting a sense for how much garbage your application is holding onto, by seeing the memory decrease in monitoring tools
  • Seeing how your application performance changes when garbage collection occurs
  • As a pre-cursor to performing some performance tests for your application

You're in luck! Node.js supports a command-line option --expose-gc that will add a function to the global object that will request garbage collection to occur. Here's an example usage in a REPL:

$ node --expose-gc
> gc()        // indirect reference to the global object
undefined
> global.gc() // direct reference to the global object
undefined

You can also pass the parameter true to the function to indicate you'd like a "full" garbage collection; without it, you'll get a "minor" garbage collection.

Note that I used the word request instead of force, regarding the garbage collection. Again, garbage collectors are a deep, mystical subject, and there is generally no 100% effective way to force garbage collection to occur - but you can request garbage collection, and typically the runtime will schedule one to occur soon.

In this blog post, we'll demonstrate an N|Solid custom command, available on npm as nsolid-command-gc, which makes use of this feature. The custom command will allow you to request garbage collection on any of your N|Solid processes using the nsolid-cli command.

Registering the N|Solid gc Custom Command in an Application

Let's do a little demo of the N|Solid gc custom command. For this demo, we'll assume that you have N|Solid installed and running on your local machine.

First, go to one of your Node.js project directories that has a valid package.json in it, so the following npm install command will install the package into that directory's node_modules directory. Then run npm install on the package:

$ cd my-current-project

$ npm install nsolid-command-gc
my-current-project@ /path/to/my-current-project
โ””โ”€โ”€ nsolid-command-gc@1.0.0

A sample application is located in the file node_modules/nsolid-command-gc/test/generate-garbage.js. This application constantly generates garbage, in the form of Buffer objects, all day long.

Next, let's set up some environment variables for N|Solid:

$ export NSOLID_APPNAME=generate-garbage
$ export NSOLID_COMMAND=9001

The first sets the name of the application, so we can locate it easily in the N|Solid Console, and with the nsolid-cli command. The second sets the N|Solid Storage command port the application should connect to.

Now let's run the sample app:

$ nsolid --expose-gc --require nsolid-command-gc node_modules/nsolid-command-gc/test/generate-garbage.js

The --expose-gc option will make the function gc() available on the global object, which the custom command needs in order to request the garbage collection. The --require nsolid-command-gc option directs the Node.js runtime to do a virtual require() on the specified module before launching the application. In this case, that module implements the custom command, and registers it with the N|Solid runtime. A path prefix is not needed for this module name, as it will be found in the node_modules directory.

Using the --require option like this is a great way to load modules which perform interesting side-effects, but that your application doesn't need to reference. The alternative would be to add the code require('nsolid-command-gc') to a module in your application, but then your application will be dependent on the custom command module. Better to leave it out of your application logic.

When the application starts, you should see the following messages:

generating garbage to test with nsolid-command-gc
(nsolid:93328) nsolid-command-gc: installing nsolid custom command "gc"
allocated 387,000,000 garbage bytes via 3,870 Buffers over 5 seconds
allocated 780,300,000 garbage bytes via 7,803 Buffers over 10 seconds
allocated 1,172,900,000 garbage bytes via 11,729 Buffers over 15 seconds
...

The message (nsolid:93328) nsolid-command-gc: installing nsolid custom command "gc" is coming from the nsolid-command-gc module itself, indicating that it has installed and registered the new gc custom command. The other messages are generated from the sample application itself.

Running the N|Solid gc custom command on an application

To run the N|Solid gc custom command, we'll need the agent id of the application. There are two easy ways to get this:

  1. Copy it out of the URL from the N|Solid Console view of the process
  2. Use the nsolid-cli ls command

For the first option, the agent id is the 40-character UUID that you can select out of the URL. Here's an example:

N|Solid Agent ID in Console

In your browser, you can just double-click anywhere within the characters of the agent id, to have the entire UUID selected, and then you can copy that to your clipboard.

For the second option, you can use the nsolid-cli ls command to list information about all your running processes. This command prints one line of JSON for every N|Solid process currently running. You can filter the list to just your application with the grep command, as so:

$ nsolid-cli ls | grep generate-garbage
{"id":"0c5ce5ea0843452edfc4e5998c86879db475ccb4","app":"generate-garbage", ...

Note that the string generate-garbage is coming from the NSOLID_APPNAME environment variable, that we set before running the application.

The id will be at the beginning, which you can select and copy into the clipboard. If you're handy with jq, you can extract the id directly:

$ nsolid-cli ls | grep generate-garbage | jq .id
"0c5ce5ea0843452edfc4e5998c86879db475ccb4"

Now that we have the agent id, let's invoke the custom command, piping the output through jq, since the output is JSON and jq will provide pretty output:

$ nsolid-cli custom --name gc --id 0c5ce5ea0843452edfc4e5998c86879db475ccb4 | jq
  {
    "result": {
    "status": "OK",
    "type": "full"
    },
    "id": "0c5ce5ea0843452edfc4e5998c86879db475ccb4",
    "app": "generate-garbage",
    "hostname": "my-hostname",
    "tags": [],
    "time": 1485188319607
  }

The nsolid-cli custom command is used to invoke all custom commands, like this one. The custom command to be invoked is specified with the --name gc option. The --id 0c5c... option specifies which N|Solid process the command should be run on.

The output of the command is a line of JSON, and the interesting bit is in the result property. In this case, the status property indicates the command was run successfully, the the type property indicates if a full or minor garbage collection was requested.

When the custom command is invoked, the program it is being invoked upon will generate some output indicating the command was run; in the example below, it's the line starting with (nsolid:93900) nsolid-command-gc:

allocated 2,772,100,000 garbage bytes via 27,721 Buffers over 35 seconds
(nsolid:93900) nsolid-command-gc: requesting full garbage collection
allocated 3,167,000,000 garbage bytes via 31,670 Buffers over 40 seconds

All the messages generated by the custom command are written using the new process.emitWarning() function in Node.js, which provides some control whether the messages are printed to stdio, and allows you to listen for them as events within your own code.

The following example shows the entire process, including showing the memory decrease in the N|Solid Console after the garbage collection occurs:

N|Solid Garbage Collection Demo

Learn more about Garbage Collection in N|Solid

For more details on using the N|Solid gc custom command within your applications, see the documentation shipped with the package.

Perhaps this blog post has gotten you thinking about other application-specific custom commands you'd like to have. N|Solid custom commands are straight-forward to implement, and the source for the gc custom command provides commentary on how to do it.

For more reference information on implementing custom commands, see the N|Solid documentation on Custom Commands.

For more information on V8's garbage collection, check out this blog post with a deep dive into how the garbage collector works.

Not ready for the production benefits of N|Solid? Kick-off your Node.js inititiatives with an Arch Eval from NodeSource and production Node.js support.