2012-03-07 138 views
3

我在我的C++应用程序中嵌入了Spidermonkey。我需要在本地C++中实现一些自定义Javascript函数,这些函数传递给jsval。我需要防止jsval意外收集垃圾。它是正确的,我做到这一点:Spidermonkey和垃圾回收

(1)在一个init程序:

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

(2)在一个C++函数执行Javascript函数的setter():

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(),因为静态jsval VP是我jsval 2个函数调用之间传递的永久存储。并且,假设以前存储在jsval中的任何JSObject都可用于垃圾收集,我会在setter()中将新值设置到gc扎根静态变量vp中。

这些正确的方法来创建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说“当你去”并显示如何将jsval分配给根。

+0

我没有看到为什么变量会在垃圾回收的风险?你能否指出这一点。 – Jivings 2012-03-07 10:45:21

+0

因为在我的Javascript脚本中,我正在调用setter()和getter之间的其他Javascript函数。请注意,setter()设置它的值,然后,另一个函数getter()获取该值。 – JavaMan 2012-03-07 10:48:14

+0

有多少功能并不重要。如果没有对它的引用,东西只会是GC。也许我不了解这个问题。你有证据表明GC正在删除你需要的变量吗? – Jivings 2012-03-07 11:04:49

回答

0

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

var x = 5;

callNativeFun(x);

function foo(){throw true; }

print(nativeFunRef());

//脚本在这里结束。 X和FOO将被垃圾回收,将会调用NativeFun和nativeFunRef js函数签名。

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

只要脚本中定义了jsval指针内容,它就永远不会到达GC。确保你的二进制代码在它的生命结束后从不使用这个值;即在脚本中完成它并调用delete时,或者将其值设置为未定义的值或代理范围终止。如果您预见到这些消极的相互作用,您应该在该jsval上设置一个GC根。

+0

也可能只是将值复制到二进制环境中,而不是将一些关键数据留在脚本之中,而这些脚本的行为是无法预测的。一般情况下,如果你需要使用GC根目录,那么除非你正在使用JS_API内部组件,否则这是错误的。 – 2012-03-31 07:59:18

0

参考SpiderMonkey的17和高达

​​或任何其他GC东西应该得到保护如果触发GC,而GC的事情是在使用的机会。即使​​引用已经受保护的存储,也需要这样做。 SpiderMonkey的GC是一个移动GC。基于基于堆​​和Heap<JS::Value>​​

使用RootedValue保护堆栈(​​相同JS::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.