You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何减少V8中频繁的Scavenge GC?

如何将V8中对象直接分配到老生代以减少Scavenge GC触发?

问题场景

我编写了一段创建百万级对象的测试代码,运行时频繁触发新生代的Scavenge GC,对性能造成了明显影响。从GC追踪日志可以看到多次Scavenge分配失败的记录,现在希望让新创建的Obj对象直接分配到老生代,从而减少Scavenge GC的触发次数。

测试代码:

function Obj ()
{
}

function genObj ()
{
  return new Obj()
}

globalThis.objPool = new Array( 1_000_000 )

function test ()
{
  globalThis.objPool.length = 0

  for ( var i = 0; i < 1_000_000; i++ )
  {
    globalThis.objPool.push( genObj() )
  }
}

test()

d8 GC追踪结果:

d8 --trace-gc  test.js   

[35164:000001B1DE2EBBA0]      120 ms: Scavenge 5.0 (5.4) -> 1.0 (2.6) MB, 5.74 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;
[35164:000001B1DE2EBBA0]      134 ms: Scavenge 2.2 (3.3) -> 1.8 (3.7) MB, 12.10 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;
[35164:000001B1DE2EBBA0]      155 ms: Scavenge 2.6 (4.1) -> 2.6 (6.6) MB, 18.12 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;
[35164:000001B1DE2EBBA0]      189 ms: Scavenge 5.7 (8.3) -> 5.2 (7.9) MB, 28.67 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;
[35164:000001B1DE2EBBA0]      231 ms: Scavenge 6.9 (9.3) -> 6.8 (15.1) MB, 36.22 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;
[35164:000001B1DE2EBBA0]      296 ms: Scavenge 12.6 (17.3) -> 12.9 (17.3) MB, 55.07 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;
[35164:000001B1DE2EBBA0]      356 ms: Scavenge 12.9 (17.3) -> 12.6 (29.3) MB, 58.69 / 0.00 ms  (average mu = 1.000, current mu = 1.000) allocation failure;
[35164:000001B1DE2EBBA0]      426 ms: Mark-Compact 17.7 (32.6) -> 14.1 (31.2) MB, 14.08 / 0.01 ms  (+ 13.4 ms in 30 steps since start of marking, biggest step 0.8 ms, walltime since start of marking 61 ms) (average mu = 1.000, current mu = 1.000) finalize incremental marking via stack guard; GC in old space requested

解决方案

  • 强制直接分配到老生代
    最直接的方式是使用d8的启动参数--force-old-space-allocation,修改运行命令为:

    d8 --trace-gc --force-old-space-allocation test.js
    

    这个参数会强制所有新创建的对象直接进入老生代内存,彻底避免新生代的Scavenge GC触发。对比修改后的GC日志,你会发现不再出现Scavenge相关记录,只会有老生代的Mark-Compact等GC操作。

  • 调整新生代内存大小减少Scavenge频率
    如果你不想全局强制所有对象进老生代,可以通过--min-semi-space-size和--max-semi-space-size参数增大新生代空间(单位为MB),减少Scavenge触发次数:

    d8 --trace-gc --min-semi-space-size=64 --max-semi-space-size=64 test.js
    

    这种方式不会改变对象分配逻辑,但更大的新生代空间能容纳更多对象,降低Scavenge的触发频率。

需要注意的是,--force-old-space-allocation属于V8的调试/测试参数,生产环境使用需谨慎——老生代GC的开销通常比新生代Scavenge更大,只有当你明确知道对象会长期存活(比如示例中对象池里的对象),这种方式才会带来性能收益。

内容的提问来源于stack exchange,提问作者printf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 18:52:36