2

関数呼び出しハンドラにデータを提供しようとしていますが、ガベージ コレクションを適切に行うことができません。

tpl->SetCallHandler(callFn, external);" "を含む行をコメントアウトすると、 ObjWeakCallbackが呼び出されます。ただし、関数が収集されることはありません (少なくともFnWeakCallbackは何があっても呼び出されません)。

プロセスごとに複数の分離に備える必要があるため、静的データはオプションではないことに注意してください。 isolate->setDataもオプションではありません。私は何かを完全に見逃していますか?内部v8::Functionにデータを保存する適切な方法は何ですか?


編集:私の意図をよりよく説明するために質問を言い換えましょう...

関数テンプレートを作成したいと思います (JS 側でコンストラクターとして使用する必要があるため)。void* をコール ハンドラに送信する方法が必要ですが、このデータはガベージ コレクション可能でなければなりません。

私がこれまでに試したことに関するいくつかのメモ:

  • の使用Function::New(isolate, callHandler, External::New(isolate, data))は機能しますが、JS 側のコンストラクター機能を提供しません (作成されたオブジェクトの SetInternalFieldCount を実行することはできません)。

  • FunctionTemplate::New(isolate, callHandler, External::New(isolate, data))コール ハンドラにデータを渡す機能を提供しますが、ガベージ コレクションは行われません (<not> 以下の動作例)。

  • 単純な関数を使用して、新しく作成した を返そうとしましたObjectが、次の仮定new Fn() instanceof Fnは失敗します


#include <v8.h>
#include <iostream>

// made static, just to simplify the example and prevent crashes
// the persistents would normally be wrapped inside a "baton" together with required data
v8::Persistent<v8::Value> p_obj;
v8::Persistent<v8::Value> p_fn;

void FnWeakCallback(const v8::WeakCallbackData<v8::Value, int>& data) {
    int* number = data.GetParameter();
    std::cout << "GC fn " << number << '\n';
    delete number;
    p_fn.Reset();
}

void ObjWeakCallback(const v8::WeakCallbackData<v8::Value, int>& data) {
    int* number = data.GetParameter();
    std::cout << "GC obj " << number << '\n';
    delete number;
    p_obj.Reset();
}

void callFn(const v8::FunctionCallbackInfo<v8::Value>& info) {
    std::cout << "called\n";
}

void test(v8::Isolate* isolate) {
    v8::HandleScope scope(isolate);

    auto external = v8::External::New(isolate, new int{ 1 });
    p_obj.Reset(isolate, external);
    p_obj.SetWeak(new int{ 1 }, ObjWeakCallback);

    auto tpl = v8::FunctionTemplate::New(isolate);
    tpl->SetCallHandler(callFn, external); // <======
    tpl->InstanceTemplate()->SetInternalFieldCount(1);
    auto fn = tpl->GetFunction();

    p_fn.Reset(isolate, fn);
    p_fn.SetWeak(new int{ 2 }, FnWeakCallback);
}

int main() {
    v8::V8::SetFlagsFromString("--expose-gc", 11);

    auto isolate = v8::Isolate::GetCurrent();
    v8::HandleScope handle_scope(isolate);
    auto context = v8::Context::New(isolate);
    context->Enter();

    test(isolate);

    isolate->RequestGarbageCollectionForTesting(v8::Isolate::kFullGarbageCollection);
    context->Exit();

    return 0;
}
4

1 に答える 1

1

今、私はだまされてコードを見ました

void GCController::CollectAll(const gin::Arguments& args) {
// In order to collect a DOM wrapper, two GC cycles are needed.
// In the first GC cycle, a weak callback of the DOM wrapper is called back
// and the weak callback disposes a persistent handle to the DOM wrapper.
// In the second GC cycle, the DOM wrapper is reclaimed.
// Given that two GC cycles are needed to collect one DOM wrapper,
// more than two GC cycles are needed to collect all DOM wrappers
// that are chained. Seven GC cycles look enough in most tests.

したがって、答えは次のとおりです。最初のコレクションの後は何も表示されません。

于 2014-09-23T20:28:24.233 に答える