2016-10-18 19 views
0

私はこの高頻度生産システムで作業しています。 C++ライブラリを呼び出すC#/ CLIレイヤがあります。私たちが観察しているのは、管理対象オブジェクトがガラベージコレクターの第2世代に入り、「つぶれている」ということです。最終的にC#アプリケーションはRAMがなくなると停止するようになります。これらの管理対象オブジェクトはローカルオブジェクトであり、非常に寿命が短くなければなりません。また、それらは一度しか参照されません。 C#アプリケーションは、すべてが強制的に削除されるようにネイティブリソースを保持するすべてのオブジェクトに対して.Dispose()を呼び出す必要があります。私たちはかなりのオブジェクトを持っているので、これは理想的ではなく、APIの観点から見ると面倒です。 CLIは次のようになります。CLIネイティブオブジェクトがgen2にスタックされ、ガベージコレクトされていない

Field::~Field() 
{ 
    if(m_pField != NULL) 
    { 
     delete m_pField; 
     m_pField = NULL; 
    } 
    System::GC::SuppressFinalize(this); 
} 

Field::!Field() 
{ 
    if(m_pField != NULL) 
    { 
     delete m_pField; 
    } 
} 

これらの短命のオブジェクトが収集されずにメモリが解放されるようなことは誰も想像できませんか?

+0

「C#/ CLI」ではなく、['C++/CLI'](https://en.wikipedia.org/wiki/C%2B%2B/CLI)と呼ばれています。正しい用語を使用することを忘れないでください。そうしないと、問題の解決策を探す際に情報を見つけることが難しくなります。 –

+0

一時的なオブジェクトが第2世代に昇格できる実際的なシナリオはあまりありません。クリスタルボールはファイナライザスレッドがデッドロックしていると言います。アンマネージデバッガで見てください。 –

+0

回顧的には、これらのことがgen 1に入り、分析が間違っていました。スコッツの推論は理にかなっています。 – UltimateDRT

答えて

3

問題は、GCがガベージコレクションのタイミングを決定するために使用する「メモリ圧」値にカウントされないことです。

管理対象ラッパーに関連付けられた大きなアンマネージドオブジェクトがあることをGCに知らせるには、GC.AddMemoryPressure(を使用します。

Field::Field() 
{ 
    //... Other stuff 

    if(m_pField != NULL) 
    { 
     m_lSizeOfField = GetSizeOfField(m_pField); 
     System::GC::AddMemoryPressure(m_lSizeOfField); 
    } 
} 


Field::~Field() 
{ 
    //If you had managed objects you would call "delete" here on them. 
    //delete m_managedData; 

    //In C++/CLI if you have unmanged resources just have the dispose method 
    // call the finalizer. It is cleaner and easier to maintain. 
    // You can't do this in C# 
    this->!Field(); 

    //No need to add this next line, C++/CLI does it for you. 
    //System::GC::SuppressFinalize(this); 
} 

Field::!Field() 
{ 
    if(m_pField != NULL) 
    { 
     delete m_pField; 
     m_pField = NULL; 
     System::GC::RemoveMemoryPressure(m_lSizeOfField); 
    } 
} 
+0

代替手段はありますか?私たちのネイティブオブジェクトのいくつかのサイズを見つけることは、非常に難解で正確な科学ではありません。 – UltimateDRT