Как да създавате, обработвате и унищожавате JS::Heap‹T› обекти в Spidermonkey?

Използване на Spidermonkey 24, 38, 45

Документацията на Spidermonkey казва: „GC нещо указва на heap трябва да бъде обвит в JS::Heap. Единственото изключение от това е, ако те се добавят като корени с функциите JS_AddRoot() или клас JS::PersistentRooted, но не правете това, освен ако наистина е необходимо. JS::Heap указателите също трябва да продължат да се проследяват по нормалния начин, който не е разгледан тук."

Какво точно означава трасиране в случая? Липсва ли нещо в следния код?

struct Foo
{
   Foo(JS::HandleObject bar) : _bar(bar) {}  // Does that root bar?
   ~Foo() {_bar = nullptr;}                  // Does that release memory?

   JS::Heap<JSObject*>  _bar;
};

Foo *create(JSContext *jscontext, JSObject *parent)
{
   JS::RootedObject bar(jscontext, JS_NewObject(jscontext, &SOME_CLASS, NULL, parent));
   return new Foo(bar);
}

Трябва ли да добавя "проследяване"? Трябва ли да руутвам обект на лента, когато се съхранява във Foo? Трябва ли да използвам функциите JS_AddRoot() за root лента, вместо да използвам Heap?


person dmitri    schedule 10.12.2014    source източник


Отговори (2)


JS::Heap<T> се използват в структури от данни, които се намират в купчината. Проследяването наистина е изискване. Без него GC може или да определи, че вашият обект е недостъпен, или да го премести, без да актуализира вашия JS::Heap<T> манипулатор.

Проследяването на обекти в spidermonkey е просто. Трябва да поискате допълнителен GC root tracer, като използвате JS_AddExtraGCRootsTracer(JSRuntime* rt, JSTraceDataOp traceOp, void* data). JSTraceDataOp е указател на функция с интерфейс void traceOp(JSTracer* trc, void* data). Във вашата функция трябва да извикате различните JS_Call<T>Tracer (дефинирани в Tracer.h) методи, предавайки трасиращия и вашия обект. Освен това трябва да се обадите на JS_TraceChildren, ако е необходимо.

Използвайки вашия пример, добавянето на проследяващ елемент може да изглежда по следния начин.

Foo* ref = create(cx, nullptr);

void trace_foos(JSTracer* tracer, void* data) {
   JS_CallHeapObjectTracer(tracer, &(ref->_bar), "foo");
}

JS_AddExtraGCRootsTracer(rt, trace_foos, nullptr);

Всеки път, когато GC се изпълнява, вашето обратно извикване за проследяване ще се изпълнява и вие трябва да преминете през обектната си графика и да проследявате GC нещата, докато вървите.

Колкото до въпросите във вашите коментари -

   Foo(JS::HandleObject bar) : _bar(bar) {}  // Does that root bar?

bar вече се корени в стека от лентата JS::RootedObject в Foo* create. Heap<T> манипулаторите не са корени - ето защо те трябва да бъдат проследени. Веднага щом create се върне, обектът вече не е руутнат.

  ~Foo() {_bar = nullptr;}                  // Does that release memory?

_bar е само екземпляр на манипулатора JS::Heap<T>. Това, към което сочи, ще бъде боклук, събран в следващ цикъл.

person jwilm    schedule 15.01.2015
comment
Забележка: Считам, че JS::TraceEdge трябва да се използва в най-новата версия на SM вместо вече остарелия JS_CallObjectTracer. (И JSContext * вместо JSRuntime *) - person James Stortz; 11.08.2018

Въз основа на отговора на jwilm тук е пример за внедряване на клас Foo.

void trace_obj(JSTracer* tracer, void* data)
{
    JS_CallObjectTracer(tracer, (JS::Heap<JSObject*>*)data, "jsobj");
}

class Foo                                                                                                                                                                             
{                                                                                                                                                                                     
public:                                                                                                                                                                               
   Foo(JSRuntime *rt, JS::HandleObject bar)                                                                                                                                           
     : _rt(rt),                                                                                                                                                                        
     _bar(bar)                                                                                                                                                                      
   {                                                                                                                                                                                  
     if (_bar.get())                                                                                                                                                                  
       JS_AddExtraGCRootsTracer(_rt, trace_obj, &_bar);                                                                                                                               
   }                                                                                                                                                                                  
   Foo(Foo const &f)                                                                                                                                           
     : _rt(f._rt),                                                                                                                                                                        
     _bar(f._bar)                                                                                                                                                                      
   {                                                                                                                                                                                  
     if (_bar.get())                                                                                                                                                                  
       JS_AddExtraGCRootsTracer(_rt, trace_obj, &_bar);                                                                                                                               
   }                                                                                                                                                                                  
   ~Foo()                                                                                                                                                                             
   {                                                                                                                                                                                  
     if (_bar.get())                                                                                                    
       JS_RemoveExtraGCRootsTracer(_rt, trace_obj, &_bar);                                                                                 
   }                                                                                                                                                                                  

private:                                                                                                                
   JSRuntime *_rt;                                                                                                                                                                    
   JS::Heap<JSObject*> _bar;                                                                                                                                                          
};                                                                                                                                                                                    
person dmitri    schedule 06.05.2016
comment
Забележка: Считам, че JS::TraceEdge трябва да се използва в най-новата версия на SM вместо вече остарелия JS_CallObjectTracer. (И JSContext * вместо JSRuntime *) - person James Stortz; 11.08.2018