【发布时间】: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:
- 代码清理
- 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