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:
- Copy it out of the URL from the N|Solid Console view of the process
- 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:
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:
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.