为了账号安全,请及时绑定邮箱和手机立即绑定

为什么在v8中运行非常简单的脚本(嵌入c ++)会占用内存?

为什么在v8中运行非常简单的脚本(嵌入c ++)会占用内存?

炎炎设计 2021-04-10 12:16:23
我正在V8中运行一个非常简单的JavaScript脚本,该脚本已嵌入C ++程序中。该脚本只是一个数字文字:“ 12”。但是,当我在一个循环中多次运行此脚本时,我的应用程序将在20-30秒后消耗几GB的内存。我正在使用V8 7.5.160,该版本是在Windows 10下使用Visual Studio 2017构建的。我运行这段代码的原因是为了从C ++执行javascript时感觉到函数调用的开销。我正在研究将V8用作应用程序的脚本引擎,该应用程序将以很高的速度调用许多小脚本。但是内存使用让我担心。我一直在寻找手动触发垃圾收集器的方法。但据我了解,这不是必须的(而且我找不到如何执行此操作)。但是我更感兴趣的是是否可以从一开始就防止这种内存使用。我使用了V8嵌入文档(hello-world.cc)中的示例代码,并使用了一个不同的脚本,该脚本以循环方式运行该脚本并确定执行调用所需的时间:// V8 setup code, unchanged from the V8 embedding hello-world.cc.// My script:v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, "12", v8::NewStringType::kNormal).ToLocalChecked();// Compile script: v8::Local<v8::Script> script = v8::Script::Compile(context, source).ToLocalChecked();// Then this code in two nested loops, where the inner loop times the time it takes.// The outer loop runs 20 times. The inner loop runs 100.000.000 times.// Inside the inner loop there is only this line of code:script->Run(context).ToLocalChecked();我期望此代码不会导致如此高的内存使用率。至少,我本来希望垃圾回收器将内存使用率保持在较低水平。非常感谢您深入了解导致此脚本使用内存的原因以及防止这种情况发生的方法。解决:jmrk提供的解决方案(谢谢!)解决了我的问题。我将运行100.000.000次的内部循环分为两个循环;一个具有100.000次迭代的外部循环和一个具有1000次迭代的内部循环。在执行此内部循环之前v8::HandleScope temp_scope(isolate);,现在不再存在极端的内存使用情况。该应用程序现在使用的内存为2.3MB。每个脚本运行的总时间也没有增加。相反,它从85ns略微降低到82ns。
查看完整描述

1 回答

?
梵蒂冈之花

TA贡献1900条经验 获得超5个赞

尝试HandleScope在调用周围使用短暂的:


for (int i = 0; i < 20; i++) {

  /* Record start time */

  for (int j = 0; j < 1000; j++) {

    v8::HandleScope temp_scope(isolate);

    for (int k = 0; k < 100000; k++) {

      script->Run(context).ToLocalChecked();

    }

  }

  /* Record end time */

}

背景是.ToLocalChecked()创建一个new v8::Local,只要当前存在,它的内容(=脚本调用的结果)就会保持活动状态HandleScope。因此,通过为一个内部的许多新对象创建许多新的句柄HandleScope,可以有效地禁用垃圾收集。


折衷是HandleScope创建/销毁具有(较小的)性能成本,但是频繁地重新创建它们会使更多的内存有资格进行垃圾回收(并且还可以稍微加快垃圾回收本身的速度)。根据经验,我的目标是每个约有1,000到1,000,000个手柄HandleScope。


查看完整回答
反对 回复 2021-04-15
  • 1 回答
  • 0 关注
  • 143 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信