6

我正在尝试使用 NDK 将 v8 嵌入到 Android 应用程序中。

我有一个看起来像这样的 JNI 模块(未显示 JNI 映射代码):

#include <jni.h>
#include <android/log.h>

#include <v8.h>
using namespace v8;

static jlong getMagicNumber() {
  HandleScope handle_scope;
  Persistent<Context> context = Context::New();
  Context::Scope context_scope(context);

  Handle<String> source = String::New("40 + 2");

  Handle<Script> script = Script::Compile(source);
  Handle<Value> result = script->Run();

  context.Dispose();

  return result->NumberValue();
}

我第一次运行时getMagicNumber,它正确运行并返回 42。我第二次尝试运行它时,它崩溃了。

具体来说,这ASSERT在 v8 中看到的isolate.h失败:

// Returns the isolate inside which the current thread is running.
INLINE(static Isolate* Current()) {
  Isolate* isolate = reinterpret_cast<Isolate*>(
      Thread::GetExistingThreadLocal(isolate_key_));
  ASSERT(isolate != NULL);
  return isolate;
}

这听起来很像这个问题,它建议使用v8::Locker来获得“对隔离的独占访问权”。

Locker l;通过在 的顶部添加一个简单的getMagicNumber,不再发生崩溃。当我不注意时,容易解决的问题往往会自行解决。

我对为什么这能解决我的问题只有最微不足道的理解,而且我收到了编译器警告,我正在v8::Locker以不推荐的方式使用它们。推荐的方法是为它提供 av8::Isolate作为v8::Locker构造函数的参数,但我不知道我应该如何“获得”一个隔离。

最终:根据 v8 的当前状态,解决此问题的正确方法是什么,为什么

4

2 回答 2

7

据我了解,V8 隔离是 V8 运行时的一个实例,包含一个堆、一个垃圾收集器和零个或多个 V8 上下文。隔离不是线程安全的,必须通过v8::Locker.

一般来说,要使用 V8,您必须首先创建一个隔离:

v8::Isolate* isolate = v8::Isolate::New();

然后,要使用任何线程的隔离:

v8::Locker locker(isolate);
v8::Isolate::Scope isolateScope(isolate);

此时线程拥有隔离,可以自由创建上下文、执行脚本等。

现在,为了非常简单的应用程序的好处,V8 提供了默认隔离并放宽了锁定要求,但是如果您始终从同一个线程访问 V8,则只能使用这些拐杖。我的猜测是您的应用程序失败了,因为第二次调用是从不同的线程进行的。

于 2013-03-24T20:07:30.680 回答
2

我现在只是在学习 V8,但我认为你需要调用:

v8::Locker locker(隔离);

这将创建一个堆栈分配的 Locker 对象,该对象将阻止 Isolate 在另一个线程上使用。当当前函数返回此堆栈对象的析构函数时,将自动调用导致 Isolate 被解锁。

您需要致电:

v8::Isolate::ScopeisolateScope(isolate);

这会将当前线程设置为运行此 Isolate。隔离只能在一个线程上使用。Locker 强制执行此操作,但 Isolate 本身需要为当前线程配置。这将创建一个堆栈分配对象,该对象指定哪个 Isolate 与当前线程相关联。就像 Locker 一样,当此变量超出范围时(当当前函数返回时),将调用 Scope 析构函数以取消将 Isolate 设置为默认值。我相信这是必要的,因为许多 V8 API 调用需要对 Isolate 的引用,但不要将其作为参数。因此他们需要一个他们可以直接访问的(可能通过每个线程变量)。

Isolate::Scope 类所做的只是在构造函数中调用isolate::Enter() 并在析构函数中调用isolate::Exit()。因此,如果您想要更多控制权,您可以自己调用 Enter()/Exit()。

于 2014-11-07T20:30:52.400 回答