2012-03-07 142 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.