我将蜘蛛侠嵌入到我的C++应用程序中。我需要在本机C++中实现一些通过jsval传递的定制Javascript函数。我需要保护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(),因为静态jsval是在两个函数调用之间传递的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写着“根随”,并展示了如何将jsval分配给根用户。
发布于 2012-03-31 07:27:32
不需要为jsval这样的东西添加根。只需维护对脚本中值的引用即可。SpiderMonkey GC是基于参考计数的,因此只要在当前范围中引用它们,您的jsval就不会消失:
变量x= 5;
callNativeFun(x);
函数foo() {抛出true;}
打印(nativeFunRef());
//脚本在这里结束。X和FOO将被垃圾收集,callNativeFun和nativeFunRef js函数签名也会被垃圾收集。
在上面的代码示例中,x和foo都由全局对象引用。
只要在脚本中定义了jsval指针内容,它就永远不会到达GC。确保二进制代码在其生命周期结束后永远不会使用该值;也就是说,当您在脚本中使用它并调用delete或将其值设置为由作用域终止的值或代理定义的值时。如果您忽略了这些负面交互,您应该在jsval上设置GC根。
发布于 2014-03-03 02:07:10
指SpiderMonkey 17及以上
如果在使用GC时有可能触发GC,则应该保护jsval
或任何其他GC设备。这是必需的,即使jsval
指的是已经受到保护的存储。蜘蛛侠的GC是一个移动GC。
使用RootedValue
保护基于堆栈的jsval
和基于堆的jsval
的Heap<JS::Value>
(jsval
与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.
https://stackoverflow.com/questions/9599589
复制相似问题