【问题标题】:Spidermonkey and Garbage Collection蜘蛛猴和垃圾收集
【发布时间】:2012-03-24 20:51:52
【问题描述】:

我将 Spidermonkey 嵌入到我的 C++ 应用程序中。我需要在本机 C++ 中实现一些自定义 Javascript 函数,这些函数传递一个 jsval。我需要保护 jsval 免受意外垃圾收集。我这样做是否合适:

(1) 在初始化例程中:

static jsval vp; // a STATIC variable, value unknown
JSBool init((JSContext *cx, uintN argc, jsval *vp) {
   JS_AddValueRoot(cx,  &vp);
}

(2)在一个实现Javascript函数setter()的c++函数中:

JSBool setter(JSContext *cx, uintN argc, jsval *vp) {
   ...
  vp=...;// set to some JSObject and hopefully makes any previous JSObject available for gc

}

(3) 在实现 Javascript 函数 getter() 的同一编译单元内的第二个 C++ 函数调用中:

JSBool getter(JSContext *cx, uintN argc, jsval *vp) {
  jsval somethingelse = vp; //directly retrieve the static value stored by setter()
  ....
}

我的 Javascript 脚本使用这样的函数调用:

init();
setter(...);
some_other_function_call_that_causes_gc();
getter();
setter(...);
some_other_function_call_that_causes_gc();
getter();
....
some_other_function_call_that_causes_gc();
setter(...);
some_other_function_call_that_causes_gc();
getter();

请注意,我从不调用 JS_RemoveRoot(),因为 static jsval vp 是我在 2 个函数调用之间传递的 jsval 的永久存储。而且,我不断在我的 setter() 中为 gc 根静态变量 vp 设置新值,假设存储在 jsval 中的任何先前的 JSObject 都可用于垃圾收集。

这些是创建可以跨函数调用传递的 gc 根临时变量的正确方法吗?特别是,我的 setter() 替换以前的 JSObject 的方式是使现有 JSObject 可用于 gc 的正确方法(即没有内存泄漏/崩溃)。

编辑:我认为垃圾收集是一个问题的原因是:

https://developer.mozilla.org/En/SpiderMonkey/JSAPI_User_Guide

在 JSAPI 概念、Javascript 值部分下:

jsval 本身并不能保护其所指对象免受垃圾的影响 收集器

https://developer.mozilla.org/en/SpiderMonkey_Garbage_Collection_Tips

示例 3 说“Root as you go”,并展示了如何将 jsval 分配给 root。

【问题讨论】:

  • 我不明白为什么该变量会面临垃圾收集的风险?你能指出来吗?
  • 因为在我的 Javascript 脚本中,我在 setter() 和 getter 之间调用了其他一些 Javascript 函数。请注意,setter() 设置它的值,稍后,另一个函数 getter() 获取该值。
  • 函数有多少并不重要。如果没有对它的引用,那么某些东西只会是 GC。也许我不明白这个问题。您是否有证据表明 GC 正在删除您需要的变量?
  • 我不确定。我对蜘蛛猴完全陌生。但是 JSAPI 用户指南说, jsval 不能保护其所指对象免受 gc 的影响。因此,即使我的 jsval 引用了一个 JSObject,该 JSObject 也可以被 gc'ed 并且我的 jsval 成为一个悬空指针。请参阅我的编辑。

标签: javascript garbage-collection spidermonkey


【解决方案1】:

不需要为 jsval 之类的东西添加根。您只需要在脚本中维护对值的引用。 SpiderMonkey GC 是基于引用计数的,因此只要在当前范围内引用它们,您的 jsval 就不会消失:

变量 x = 5;

调用NativeFun(x);

function foo() { 抛出 true; }

打印(nativeFunRef());

//脚本到此结束。 X 和 FOO 将像 callNativeFun 和 nativeFunRef js 函数签名一样被垃圾回收。

在上面的代码示例中,x 和 foo 都被全局对象引用。

只要脚本中定义了 jsval 指针内容,它就永远不会到达 GC。确保您的二进制代码在其生命周期结束后永远不会使用该值;也就是说,当您在脚本中完成它并对其调用 delete 或将其值设置为未定义的值或范围终止代理时。如果您预见到任何这些负面交互,您应该在该 jsval 上设置 GC 根。

【讨论】:

  • 您也可能只想将值复制到二进制环境,而不是将一些关键数据留在脚本手中,脚本的行为您无法预测。通常,如果您需要 GC root 某些东西,除非您使用 JS_API 内部,否则您的做法是错误的。
【解决方案2】:

参考 SpiderMonkey 17 及更高版本

jsval 或任何其他 GC 事物应该受到保护,如果在使用 GC 事物时有可能触发 GC。即使jsval 指的是已受保护的存储,这也是必需的。 SpiderMonkey 的 GC 是一个移动 GC

使用RootedValue 保护基于堆栈的jsvalHeap<JS::Value> 保护基于堆的jsval
jsvalJS::Value 相同)。使用Handle<JS::Value>MutableHandle<JS::Value> 作为函数的参数。

以下是 RootingAPI cmets 的摘录:

 * A moving GC may change the physical location of GC allocated things, even
 * when they are rooted, updating all pointers to the thing to refer to its new
 * location. The GC must therefore know about all live pointers to a thing,
 * not just one of them, in order to behave correctly.
 *
 * For a code fragment such as:
 *
 * JSObject *obj = NewObject(cx);
 * DoSomething(cx);
 * ... = obj->lastProperty();
 *
 * If |DoSomething()| can trigger a GC, the stack location of |obj| must be
 * rooted to ensure that the GC does not move the JSObject referred to by
 * |obj| without updating |obj|'s location itself. This rooting must happen
 * regardless of whether there are other roots which ensure that the object
 * itself will not be collected.
 *
 * If |DoSomething()| cannot trigger a GC, and the same holds for all other
 * calls made between |obj|'s definitions and its last uses, then no rooting
 * is required.
 *
 * SpiderMonkey can trigger a GC at almost any time and in ways that are not
 * always clear. For example, the following innocuous-looking actions can
 * cause a GC: allocation of any new GC thing; JSObject::hasProperty;
 * JS_ReportError and friends; and ToNumber, among many others. The following
 * dangerous-looking actions cannot trigger a GC: js_malloc, cx->malloc_,
 * rt->malloc_, and friends and JS_ReportOutOfMemory.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-03
    • 2012-03-21
    • 2013-01-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多