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

Использование Обезьяны-паука 24, 38, 45

В документация Spidermonkey говорится: "Указатели GC на куча должна быть заключена в 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() для корневой панели вместо использования кучи?


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


Ответы (2)


JS::Heap<T> используются в структурах данных, которые находятся в куче. Отслеживание действительно является обязательным требованием. Без него сборщик мусора может либо определить, что ваш объект недоступен, либо переместить его без обновления дескриптора JS::Heap<T>.

Отслеживать объекты в spidermonkey очень просто. Вам нужно запросить дополнительный корневой трассировщик GC, используя 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);

Всякий раз, когда запускается сборщик мусора, будет выполняться ваш обратный вызов трассировки, и вы должны просматривать граф объектов и отслеживать действия сборщика мусора по ходу дела.

Что касается вопросов в ваших комментариях -

   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
Примечание. Я считаю, что в последней версии SM следует использовать JS::TraceEdge вместо устаревшего 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
Примечание. Я считаю, что в последней версии SM следует использовать JS::TraceEdge вместо устаревшего JS_CallObjectTracer. (И JSContext * вместо JSRuntime *) - person James Stortz; 11.08.2018