5

わかりましたので、正確な「マークとスイープ」ガベージ コレクターを C++ で書きたいと思っています。すべてのポインターが「RelocObject」にラップされ、ヒープ用に単一のメモリブロックがあるため、役立つ決定を下したことを願っています。これは次のようになります。

// This class acts as an indirection to the actual object in memory so that it can be      
// relocated in the sweep phase of garbage collector
class MemBlock
{
public:
    void* Get( void ) { return m_ptr; }

private:
    MemBlock( void ) : m_ptr( NULL ){}

    void* m_ptr;
};

// This is of the same size as the above class and is directly cast to it, but is     
// typed so that we can easily debug the underlying object
template<typename _Type_>
class TypedBlock
{
public:
    _Type_* Get( void ) { return m_pObject; }

private:
    TypedBlock( void ) : m_pObject( NULL ){}

    // Pointer to actual object in memory
    _Type_* m_pObject;
};

// This is our wrapper class that every pointer is wrapped in 
template< typename _Type_ >
class RelocObject
{
public:

    RelocObject( void ) : m_pRef( NULL ) {}

    static RelocObject New( void )
    {
        RelocObject ref( (TypedBlock<_Type_>*)Allocator()->Alloc( this, sizeof(_Type_), __alignof(_Type_) ) );
        new ( ref.m_pRef->Get() ) _Type_();
        return ref;
    }

    ~RelocObject(){}

    _Type_*     operator->  ( void ) const 
    { 
        assert( m_pRef && "ERROR! Object is null\n" ); 
        return (_Type_*)m_pRef->Get(); 
    }

    // Equality
    bool operator ==(const RelocObject& rhs) const { return m_pRef->Get() == rhs.m_pRef->Get(); }
    bool operator !=(const RelocObject& rhs) const { return m_pRef->Get() != rhs.m_pRef->Get(); }

    RelocObject&    operator=   ( const RelocObject& rhs ) 
    {
        if(this == &rhs) return *this;
        m_pRef = rhs.m_pRef;
        return *this; 
    }

private:

    RelocObject( TypedBlock<_Type_>* pRef ) : m_pRef( pRef ) 
    {
        assert( m_pRef && "ERROR! Can't construct a null object\n");
    }

    RelocObject*    operator&   ( void ) { return this; }
    _Type_&     operator*   ( void ) const { return *(_Type_*)m_pRef->Get(); }

    // SS: 
    TypedBlock<_Type_>* m_pRef;
};

// We would use it like so...
typedef RelocObject<Impl::Foo> Foo;

void main( void )
{
    Foo foo = Foo::New();
}

したがって、「RelocObject::New」で割り当てるときに「ルート」RelocObjects を見つけるために、RelocObject の「this」ポインターをアロケーター (ガベージ コレクター) に渡します。次に、アロケータは、「this」ポインタがヒープのメモリ ブロックの範囲内にあるかどうかを確認します。範囲内にある場合は、ルートではないと見なすことができます。

そのため、各子オブジェクト内にある 0 個以上の RelocObjects を使用して、ルートから子オブジェクトまでトレースしたい場合に問題が発生します。

「正確な」メソッドを使用して、クラス (つまり、子オブジェクト) 内の RelocObjects を見つけたいと考えています。リフレクション アプローチを使用して、各クラスの RelocObjects がある場所にユーザーを登録させることができます。ただし、これは非常にエラーが発生しやすいため、これを自動的に行いたいと考えています。

その代わりに、Clang を使用してコンパイル時にクラス内の RelocObjects のオフセットを見つけ、プログラムの開始時にこの情報をロードし、これをガベージ コレクターのマーク フェーズで使用してトレースし、子オブジェクトをマークすることを検討しています。

私の質問は、Clang が役に立ちますか? コンパイル時のフックを使用して、コンパイル中にあらゆる種類の型情報を収集できると聞きました。もしそうなら、私はClangで何を探すべきですか?つまり、この種のことを行う例はありますか?

明確にするために、Clangを使用して、ユーザーが「ヒント」を提供することなく、FooBで「Foo」(RelocObjectのtypedef)のオフセットを自動的に見つけたい、つまり、次のように記述します。

class FooB
{
public:
    int m_a;
    Foo m_ptr;
};

助けてくれてありがとう。

4

1 に答える 1

1

RelocObjectがインスタンス化されるたびに、そのアドレスをRelocObject所有権データベースに記録できます。これにより、どれがどの に属しているsizeof(*derivedRelocObject)かがすぐに識別されます。そのためにClangは必要ありません。また、は の直後に作成されるため、 「作成されました。ここに私のアドレスとサイズがあります」という呼び出しの順序で、所有しているインスタンスの直前に所有レコードが表示されるため、所有権データベース システムは非常に単純になります。FooFooBFooFooBRelocObjectRelocObject

それぞれRelocObjectには、最初の使用時に false として初期化されたownership_been_declaredフラグがあります (コンストラクターで実際の作業を行う必要がないため、コンストラクターが完了した後になります)。したがって、これらの新しく作成されたオブジェクトのいずれかが最初に使用されると、データベースの更新が要求されます。それは所有権であり、データベースは記録されたアドレスのキューを通過し、どのオブジェクトがどのオブジェクトに属しているかを識別し、リストからいくつかをクリアし、それらのownership_been_declaredフラグをtrueに設定すると、オフセットも取得できます(まだ必要な場合)。


ps 必要に応じて、私が何年も前に書いたインクリメンタル ガベージ コレクターのコードを共有できます。

于 2012-04-17T14:36:16.030 に答える