【问题标题】:V8 Embedded, Segmentation Fault after more run iterationV8 Embedded,多次运行迭代后出现分段错误
【发布时间】:2021-09-22 13:39:13
【问题描述】:

我正在尝试在 C++ 中使用 v8,我想在主线程中编译 js 代码,然后将 compiled_script 传递给执行程序(子线程)。 Run 执行过程将在线程中运行。

故事:编译过程很昂贵,我需要性能,因此我会在开始时缓存所有编译的脚本,并将它们传递给不同的线程执行。

为了测试这个场景,我只创建了一个线程并将编译后的脚本传递给它,在for 循环中进行了 1500 次迭代后,程序以 Segmentation Fault Error 退出。

问题与线程有关,如果我将执行移到线程外,它将成功结束。

我进行了更多调查,但找不到任何解决方案。

完整代码:

#include "include/libplatform/libplatform.h"
#include "include/v8.h"
#include <future>
#include <iostream>
#include <string>
#include <thread>

bool ExecuteScript(v8::Isolate *isolate,
                   v8::MaybeLocal<v8::Script> compiled_script) {

  v8::HandleScope handle_scope(isolate);
  v8::TryCatch try_catch(isolate);
  v8::Local<v8::Context> context(isolate->GetCurrentContext());

  v8::Local<v8::Value> result;
  v8::Local<v8::Script> c = compiled_script.FromMaybe(v8::Local<v8::Script>());
  if (c.IsEmpty())
    std::cout << "Compile Script is Empty" << std::endl;
  if (context.IsEmpty())
    std::cout << "Conetxt is Empty" << std::endl;
  auto x = c->Run(context);
  if (!x.ToLocal(&result)) {
    v8::String::Utf8Value error(isolate, try_catch.Exception());
    std::cout << *error << std::endl;
    return false;
  }
  return true;
}

v8::MaybeLocal<v8::Script> CompileScript(v8::Isolate *isolate,
                                         v8::Local<v8::String> raw_source) {
  v8::ScriptCompiler::Source source(raw_source);
  auto unboundedScript =
      v8::ScriptCompiler::CompileUnboundScript(
          isolate, &source,
          v8::ScriptCompiler::CompileOptions::kNoCompileOptions)
          .ToLocalChecked();

  return unboundedScript->BindToCurrentContext();
}

int main() {
  v8::Isolate::CreateParams create_params;
  v8::Isolate *isolate;
  std::unique_ptr<v8::Platform> platform;
  v8::Global<v8::Context> context_;

  v8::V8::InitializeICUDefaultLocation(".");
  v8::V8::InitializeExternalStartupData(".");
  platform = v8::platform::NewDefaultPlatform();
  v8::V8::InitializePlatform(platform.get());
  v8::V8::Initialize();

  create_params.array_buffer_allocator =
      v8::ArrayBuffer::Allocator::NewDefaultAllocator();
  isolate = v8::Isolate::New(create_params);
  v8::Isolate::Scope isolate_scope(isolate);
  v8::HandleScope scope(isolate);

  v8::Local<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);

  v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global);
  context_.Reset(isolate, context);

  {

    auto tt = std::async(std::launch::async, [&]() {
      v8::Locker locker(isolate);
      v8::HandleScope thread_scope(isolate);
      v8::Context::Scope context_scope(context);
      v8::MaybeLocal<v8::Script> compliedScript = CompileScript(
          isolate,
          v8::String::NewFromUtf8Literal(isolate, "var j=0; while(j<5) j++; "));
      for (int i = 0; i < 1000000; i++) {
        std::cout << i << std::endl;
        if (!ExecuteScript(isolate, compliedScript)) {
          std::cout << "Execution Error" << std::endl;
          return;
        }
      }
    });
    tt.wait();
  }

  v8::V8::Dispose();
  v8::V8::ShutdownPlatform();
  delete create_params.array_buffer_allocator;
  std::cout << "Exit Normal" << std::endl;
  return 0;
}

我该如何解决这个问题?

编辑1:

  1. 代码清理
  2. valgrind 内存泄漏结果:
==2588106== Warning: set address range perms: large range [0x2bf200000000, 0x2bf400000000) (noaccess)
==2588106== Warning: set address range perms: large range [0x2bf200000000, 0x2bf400000000) (noaccess)
==2588106== Warning: set address range perms: large range [0x2bf200000000, 0x2bf300000000) (noaccess)==2588106== Thread 9:
==2588106== Invalid read of size 8
==2588106==    at 0x2D7B24: v8::internal::Isolate::main_thread_local_heap() (in /home/linux/v8)
==2588106==    by 0x3F07EA: v8::internal::interpreter::BytecodeArrayIterator::BytecodeArrayIterator(v8::internal::Handle<v8::internal::BytecodeArray>, int) (in /home/linux/v8)
==2588106==    by 0xD7EC2B: v8::internal::compiler::BytecodeGraphBuilder::BytecodeGraphBuilder(v8::internal::compiler::JSHeapBroker*, v8::internal::Zone*, v8::internal::compiler::NativeContextRef const&, v8::internal::compiler::SharedFunctionInfoRef const&, v8::internal::compiler::FeedbackCellRef const&, v8::internal::BytecodeOffset, v8::internal::compiler::JSGraph*, v8::internal::compiler::CallFrequency const&, v8::internal::compiler::SourcePositionTable*, int, v8::internal::CodeKind, v8::base::Flags<v8::internal::compiler::BytecodeGraphBuilderFlag, int>, v8::internal::TickCounter*, v8::internal::compiler::ObserveNodeInfo const&) (in /home/linux/v8)
==2588106==    by 0xD92621: v8::internal::compiler::BuildGraphFromBytecode(v8::internal::compiler::JSHeapBroker*, v8::internal::Zone*, v8::internal::compiler::SharedFunctionInfoRef const&, v8::internal::compiler::FeedbackCellRef const&, v8::internal::BytecodeOffset, v8::internal::compiler::JSGraph*, v8::internal::compiler::CallFrequency const&, v8::internal::compiler::SourcePositionTable*, int, v8::internal::CodeKind, v8::base::Flags<v8::internal::compiler::BytecodeGraphBuilderFlag, int>, v8::internal::TickCounter*, v8::internal::compiler::ObserveNodeInfo const&) (in /home/linux/v8)
==2588106==    by 0x80E6FD: v8::internal::compiler::GraphBuilderPhase::Run(v8::internal::compiler::PipelineData*, v8::internal::Zone*) (in /home/linux/v8)
==2588106==    by 0x7FFE81: void v8::internal::compiler::PipelineImpl::Run<v8::internal::compiler::GraphBuilderPhase>() (in /home/linux/v8)
==2588106==    by 0x7FC747: v8::internal::compiler::PipelineImpl::CreateGraph() (in /home/linux/v8)
==2588106==    by 0x7FC10F: v8::internal::compiler::PipelineCompilationJob::PrepareJobImpl(v8::internal::Isolate*) (in /home/linux/v8)
==2588106==    by 0x253924: v8::internal::OptimizedCompilationJob::PrepareJob(v8::internal::Isolate*) (in /home/linux/v8)
==2588106==    by 0x25F4E5: v8::internal::(anonymous namespace)::GetOptimizedCodeLater(std::unique_ptr<v8::internal::OptimizedCompilationJob, std::default_delete<v8::internal::OptimizedCompilationJob> >, v8::internal::Isolate*, v8::internal::OptimizedCompilationInfo*, v8::internal::CodeKind, v8::internal::Handle<v8::internal::JSFunction>) (in /home/linux/v8)
==2588106==    by 0x25862D: v8::internal::(anonymous namespace)::GetOptimizedCode(v8::internal::Handle<v8::internal::JSFunction>, v8::internal::ConcurrencyMode, v8::internal::CodeKind, v8::internal::BytecodeOffset, v8::internal::JavaScriptFrame*) (in /home/linux/v8)
==2588106==    by 0x259905: v8::internal::Compiler::CompileOptimized(v8::internal::Isolate*, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::ConcurrencyMode, v8::internal::CodeKind) (in /home/linux/v8)
==2588106==  Address 0xc1f8 is not stack'd, malloc'd or (recently) free'd
==2588106==
==2588106==
==2588106==  Access not within mapped region at address 0xC1F8
==2588106==    at 0x2D7B24: v8::internal::Isolate::main_thread_local_heap() (in /home/linux/v8)
==2588106==    by 0x3F07EA: v8::internal::interpreter::BytecodeArrayIterator::BytecodeArrayIterator(v8::internal::Handle<v8::internal::BytecodeArray>, int) (in /home/linux/v8)
==2588106==    by 0xD7EC2B: v8::internal::compiler::BytecodeGraphBuilder::BytecodeGraphBuilder(v8::internal::compiler::JSHeapBroker*, v8::internal::Zone*, v8::internal::compiler::NativeContextRef const&, v8::internal::compiler::SharedFunctionInfoRef const&, v8::internal::compiler::FeedbackCellRef const&, v8::internal::BytecodeOffset, v8::internal::compiler::JSGraph*, v8::internal::compiler::CallFrequency const&, v8::internal::compiler::SourcePositionTable*, int, v8::internal::CodeKind, v8::base::Flags<v8::internal::compiler::BytecodeGraphBuilderFlag, int>, v8::internal::TickCounter*, v8::internal::compiler::ObserveNodeInfo const&) (in /home/linux/v8)
==2588106==    by 0xD92621: v8::internal::compiler::BuildGraphFromBytecode(v8::internal::compiler::JSHeapBroker*, v8::internal::Zone*, v8::internal::compiler::SharedFunctionInfoRef const&, v8::internal::compiler::FeedbackCellRef const&, v8::internal::BytecodeOffset, v8::internal::compiler::JSGraph*, v8::internal::compiler::CallFrequency const&, v8::internal::compiler::SourcePositionTable*, int, v8::internal::CodeKind, v8::base::Flags<v8::internal::compiler::BytecodeGraphBuilderFlag, int>, v8::internal::TickCounter*, v8::internal::compiler::ObserveNodeInfo const&) (in /home/linux/v8)
==2588106==    by 0x80E6FD: v8::internal::compiler::GraphBuilderPhase::Run(v8::internal::compiler::PipelineData*, v8::internal::Zone*) (in /home/linux/v8)
==2588106==    by 0x7FFE81: void v8::internal::compiler::PipelineImpl::Run<v8::internal::compiler::GraphBuilderPhase>() (in /home/linux/v8)
==2588106==    by 0x7FC747: v8::internal::compiler::PipelineImpl::CreateGraph() (in /home/linux/v8)
==2588106==    by 0x7FC10F: v8::internal::compiler::PipelineCompilationJob::PrepareJobImpl(v8::internal::Isolate*) (in /home/linux/v8)
==2588106==    by 0x253924: v8::internal::OptimizedCompilationJob::PrepareJob(v8::internal::Isolate*) (in /home/linux/v8)
==2588106==    by 0x25F4E5: v8::internal::(anonymous namespace)::GetOptimizedCodeLater(std::unique_ptr<v8::internal::OptimizedCompilationJob, std::default_delete<v8::internal::OptimizedCompilationJob> >, v8::internal::Isolate*, v8::internal::OptimizedCompilationInfo*, v8::internal::CodeKind, v8::internal::Handle<v8::internal::JSFunction>) (in /home/linux/v8)
==2588106==    by 0x25862D: v8::internal::(anonymous namespace)::GetOptimizedCode(v8::internal::Handle<v8::internal::JSFunction>, v8::internal::ConcurrencyMode, v8::internal::CodeKind, v8::internal::BytecodeOffset, v8::internal::JavaScriptFrame*) (in /home/linux/v8)
==2588106==    by 0x259905: v8::internal::Compiler::CompileOptimized(v8::internal::Isolate*, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::ConcurrencyMode, v8::internal::CodeKind) (in /home/linux/v8)
==2588106==  If you believe this happened as a result of a stack
==2588106==  overflow in your program's main thread (unlikely but
==2588106==  possible), you can try to increase the size of the
==2588106==  main thread stack using the --main-stacksize= flag.
==2588106==  The main thread stack size used in this run was 8388608.
==2588106==
==2588106== HEAP SUMMARY:
==2588106==     in use at exit: 541,595 bytes in 1,411 blocks
==2588106==   total heap usage: 2,072 allocs, 661 frees, 1,155,883 bytes allocated
==2588106==
==2588106== Thread 1:
==2588106== 1 bytes in 1 blocks are still reachable in loss record 1 of 1,252
==2588106==    at 0x483CFE3: operator new(unsigned long) (vg_replace_malloc.c:417)
==2588106==    by 0x330BFC: v8::internal::Heap::SetUpSpaces() (in /home/linux/v8)
==2588106==    by 0x2D60B7: v8::internal::Isolate::Init(v8::internal::SnapshotData*, v8::internal::SnapshotData*, bool) (in /home/linux/v8)
==2588106==    by 0x2D6C88: v8::internal::Isolate::InitWithSnapshot(v8::internal::SnapshotData*, v8::internal::SnapshotData*, bool) (in /home/linux/v8)
==2588106==    by 0x5F789D: v8::internal::Snapshot::Initialize(v8::internal::Isolate*) (in /home/linux/v8)
==2588106==    by 0x245612: v8::Isolate::Initialize(v8::Isolate*, v8::Isolate::CreateParams const&) (in /home/linux/v8)
==2588106==    by 0x24581C: v8::Isolate::New(v8::Isolate::CreateParams const&) (in /home/linux/v8)
==2588106==    by 0x2074BB: main (in /home/linux/v8)
==2588106==
==2588106== 1 bytes in 1 blocks are still reachable in loss record 2 of 1,252
==2588106==    at 0x483CFE3: operator new(unsigned long) (vg_replace_malloc.c:417)
==2588106==    by 0x330F6A: v8::internal::Heap::SetUpSpaces() (in /home/linux/v8)
==2588106==    by 0x2D60B7: v8::internal::Isolate::Init(v8::internal::SnapshotData*, v8::internal::SnapshotData*, bool) (in /home/linux/v8)
==2588106==    by 0x2D6C88: v8::internal::Isolate::InitWithSnapshot(v8::internal::SnapshotData*, v8::internal::SnapshotData*, bool) (in /home/linux/v8)
==2588106==    by 0x5F789D: v8::internal::Snapshot::Initialize(v8::internal::Isolate*) (in /home/linux/v8)
==2588106==    by 0x245612: v8::Isolate::Initialize(v8::Isolate*, v8::Isolate::CreateParams const&) (in /home/linux/v8)
==2588106==    by 0x24581C: v8::Isolate::New(v8::Isolate::CreateParams const&) (in /home/linux/v8)
==2588106==    by 0x2074BB: main (in /home/linux/v8)
==2588106==
==2588106== 1 bytes in 1 blocks are still reachable in loss record 3 of 1,252
==2588106==    at 0x483EA5D: operator new[](unsigned long, std::nothrow_t const&) (vg_replace_malloc.c:658)
==2588106==    by 0x53082E: v8::internal::String::ToCString(v8::internal::AllowNullsFlag, v8::internal::RobustnessFlag, int, int, int*) (in /home/linux/v8)
==2588106==    by 0x530C0A: v8::internal::String::ToCString(v8::internal::AllowNullsFlag, v8::internal::RobustnessFlag, int*) (in /home/linux/v8)
==2588106==    by 0x51AE2F: v8::internal::SharedFunctionInfo::DebugNameCStr() (in /home/linux/v8)
==2588106==    by 0x27839C: v8::internal::OptimizedCompilationInfo::GetDebugName() const (in /home/linux/v8)
==2588106==    by 0x7FB419: v8::internal::compiler::PipelineData::PipelineData(v8::internal::compiler::ZoneStats*, v8::internal::Isolate*, v8::internal::OptimizedCompilationInfo*, v8::internal::compiler::PipelineStatistics*, bool) (in /home/linux/v8)
==2588106==    by 0x7FB1FF: v8::internal::compiler::PipelineCompilationJob::PipelineCompilationJob(v8::internal::Isolate*, v8::internal::Handle<v8::internal::SharedFunctionInfo>, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::BytecodeOffset, v8::internal::JavaScriptFrame*, v8::internal::CodeKind) (in /home/linux/v8)
==2588106==    by 0x807EDA: v8::internal::compiler::Pipeline::NewCompilationJob(v8::internal::Isolate*, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::CodeKind, bool, v8::internal::BytecodeOffset, v8::internal::JavaScriptFrame*) (in /home/linux/v8)
==2588106==    by 0x2585F8: v8::internal::(anonymous namespace)::GetOptimizedCode(v8::internal::Handle<v8::internal::JSFunction>, v8::internal::ConcurrencyMode, v8::internal::CodeKind, v8::internal::BytecodeOffset, v8::internal::JavaScriptFrame*) (in /home/linux/v8)
==2588106==    by 0x259905: v8::internal::Compiler::CompileOptimized(v8::internal::Isolate*, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::ConcurrencyMode, v8::internal::CodeKind) (in /home/linux/v8)
==2588106==    by 0xB2C785: v8::internal::(anonymous namespace)::CompileOptimized(v8::internal::Isolate*, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::ConcurrencyMode) (in /home/linux/v8)
==2588106==    by 0xB28ACB: v8::internal::Runtime_CompileOptimized_Concurrent(int, unsigned long*, v8::internal::Isolate*) (in /home/linux/v8)
==2588106==
==2588106== 2 bytes in 1 blocks are still reachable in loss record 4 of 1,252
==2588106==    at 0x483EA5D: operator new[](unsigned long, std::nothrow_t const&) (vg_replace_malloc.c:658)
==2588106==    by 0x261383: v8::internal::CallDescriptors::InitializeOncePerProcess() (in /home/linux/v8)
==2588106==    by 0x3F0386: v8::internal::V8::InitializeOncePerProcessImpl() (in /home/linux/v8)
==2588106==    by 0x9ED455: v8::base::CallOnceImpl(std::atomic<unsigned char>*, std::function<void ()>) (in /home/linux/v8)
==2588106==    by 0x3EFFFD: v8::internal::V8::Initialize() (in /home/linux/v8)
==2588106==    by 0x23634A: v8::V8::Initialize(int) (in /home/linux/v8)
==2588106==    by 0x2074A2: main (in /home/linux/v8)
==2588106==
==2588106== 2 bytes in 1 blocks are still reachable in loss record 5 of 1,252
==2588106==    at 0x483EA5D: operator new[](unsigned long, std::nothrow_t const&) (vg_replace_malloc.c:658)
==2588106==    by 0x2620B0: v8::internal::CallDescriptors::InitializeOncePerProcess() (in /home/linux/v8)
==2588106==    by 0x3F0386: v8::internal::V8::InitializeOncePerProcessImpl() (in /home/linux/v8)
==2588106==    by 0x9ED455: v8::base::CallOnceImpl(std::atomic<unsigned char>*, std::function<void ()>) (in /home/linux/v8)
==2588106==    by 0x3EFFFD: v8::internal::V8::Initialize() (in /home/linux/v8)
==2588106==    by 0x23634A: v8::V8::Initialize(int) (in /home/linux/v8)
==2588106==    by 0x2074A2: main (in /home/linux/v8)

编辑 2: 编译命令:

g++ sample.cpp libv8_monolith.a -I/usr/local/include/v8/ -I/usr/local/include/v8/include/ -lpthread -o v8 -DV8_COMPRESS_POINTERS

【问题讨论】:

  • 我进行了更多调查,但找不到任何解决方案。 -- 你应该做的第一件事是弄清楚为什么会发生分段错误,而不是移动代码并希望某些东西有效。
  • 是的,你是对的,对不起,我忘了把我的 valgrind 内存检查输出。
  • (1) 请发布复制详细信息:哪个 V8 版本(git 哈希),您是如何编译的(V8 和您的应用程序)。 -- (2) 请注意,这种方法无论如何都不会扩展到多个线程:v8::Locker(这是必需的!)确保一次只有一个线程可以使用Isolate。 -- (3) 是什么让你觉得CompileScript 很慢?我希望它会非常快。
  • (1) - v8 版本是 9.1.0.0, (2) - 是的,我知道,但是在这个例子中我只创建了一个线程并使用了v8::Locker(在这个代码块中不是必需的),请参阅main(),(3) - 在我的真实情况下,我有大约 10 个脚本,我从我的一个 C++ 对象收到了很多请求(数千个),需要Run 这些脚本,并且想要撤销编译在执行期间,它显着提高了性能。

标签: c++ multithreading pthreads v8 embedded-v8


【解决方案1】:

这是 V8 9.1 版本中的一个错误,已被 google 修复。

【讨论】:

  • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-19
相关资源
最近更新 更多