蜘蛛侠和垃圾收集

时间:2012-03-07 10:19:53

标签: javascript garbage-collection spidermonkey

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

(1)在init例程中:

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 是我在两次函数调用之间传递的jsval的永久存储。并且,我继续在我的setter()中将新值设置到gc rooted静态变量vp中,假设存储在jsval中的任何先前JSObject都可用于垃圾收集。

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

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

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

在JSAPI Concepts,Javascript Values:

部分下
  

jsval本身并不能保护它的指示物免受垃圾的侵害   集电极

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

示例3说“ Root as go go ”并显示如何将jsval分配给根。

2 个答案:

答案 0 :(得分:0)

没有必要像jsval那样添加root。您只需要维护对脚本中值的引用。 SpiderMonkey GC基于参考计数,因此只要在当前范围内引用它们,您的jsvals就不会消失:

var x = 5;

callNativeFun(X);

function foo(){throw true; }

打印(nativeFunRef());

//脚本在这里结束。 X和FOO将被垃圾收集,因为callNativeFun和nativeFunRef js函数签名。

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

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

答案 1 :(得分:0)

参考SpiderMonkey 17及以上

如果在GC使用过程中有可能触发GC,则

jsval或任何其他GC事物应受到保护。即使jsval引用已受保护的存储,也需要这样做。 SpiderMonkey的GC是移动GC

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

以下是RootingAPI评论的摘录:

 * 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.