Skip to content

Increase default 'max_semi_space_size' value to reduce GC overhead in V8 #42511

Closed as not planned
@JialuZhang-intel

Description

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:

  • Advantage: throughput improvement. Because the scavenge GC occur frequency decreased, the total GC pause time will also decrease, then node can have more CPU resource to execute the javascript code.
  • Disadvantage: more memory usage. This is obviously, more semi_space size will cost more memory.

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:

  • Peak memory usage increases linearly with max_semi_space_size.
  • Throughput grows fast when max_semi_space_size less than 128MB, then keep flat when max_space_size bigger than 128MB.
  • The scale of the throughput improvement is workload-dependent, probably due to the greater GC pressure from web-tooling-benchmark.

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:

  • Hardware:
    • CPU: Intel(R) Xeon(R) Platinum 8358 CPU @ 2.60GHz
    • RAM: 500GB
  • Software:
    • OS: Ubuntu 20.04.1 (x86_64)
    • Linux version: 5.11.0-41-generic
    • Docker version: 20.10.11
    • node version: v18.0.0-pre

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    feature requestIssues that request new features to be added to Node.js.help wantedIssues that need assistance from volunteers or PRs that need help to proceed.stalev8 engineIssues and PRs related to the V8 dependency.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions