Increase default 'max_semi_space_size' value to reduce GC overhead in V8 · Issue #42511 · nodejs/node (original) (raw)

What is the problem this feature will solve?

When I use node to run the web-tooling-benchmark, I found that the runtime flag --max_semi_space_size have a big impact on the test result. The total throughput increased about 18% after I pass the runtime flag --max_semi_space_size=128 into node. So I did some investigate about the 'max_semi_space_size' flag.

From some v8 official blogs (Getting garbage collection for free, orinoco-parallel-scavenger), I found there are two garbage collection strategies in V8:

Scavenge GC: fast, high frequency, for young generation objects.

Major GC: take a long time, low frequency, full garbage collections.

When we create a new object by javascript code, the object will be put into semi_space as a young generation object. And when the semi_space is about to use up, V8 engine will trigger the Scavenge GC to clean up the garbage objects in semi_space.

If I use the --max_semi_space_size flag to increase the maximum limit of semi_space size, the scavenge GC occur frequency will decrease. This will bring both advantages and disadvantages:

It's a trade-off between time and space. V8 set the default max_semi_space_size as 16MB for 64bit system and 8MB for 32bit system (related code). I think it's a heuristic value that mainly considered client device with small RAM size (for example: some android device only have 4GB RMA). But for server scenarios, memory usually isn't the bottleneck, while throughput is the actual bottleneck.

So the problem is:

Whether the currently default max_semi_space_size(16MB/8MB) for V8 is also the best configuration for node?

What is the feature you are proposing to solve the problem?

To solve the problem above, I tuned the --max_semi_space_size (16MB, 32MB, 64MB, 128MB, 256MB) and tested on web-tooling-benchmark and a simple service based on ghost.js. Here is the test results:

image

From the figure we can see that:

So I think we can choose a better max_semi_space_size value and pass this runtime flag to V8 when node startup.

What alternatives have you considered?

Test environment:

Test process:

  1. Build the docker container with node binary and workload in it.
  2. Start multi-containers (containers number equals vCPU number) to make sure the system's total CPU usage rate >90%.
  3. Running the workload in started containers concurrently and monitor the system's total memory usage periodically.