2

現在取り組んでいるプロジェクトのデザイン候補を考え出そうとしています。そのクライアント インターフェイスは、パブリック メソッドとコールバックを公開する WCF サービスに基づいています。リクエストは、計算や操作などを実行する C++ ライブラリ (boost を使用する) にルーティングされます。

現在のスキームは、IPC を介して別のネイティブ C++ プロセスと通信する WCF サービスに基づいています。

もう少し簡単にするために、ここでは混合モードにすることをお勧めします (つまり、ネイティブ C++ レイヤーをロードする単一の .NET プロセスを持ち、ほとんどの場合、非常に薄い C++/CLI レイヤーを介して通信します)。 . 主な懸念事項は、ガベージ コレクションまたはその他の .NET の側面が、プロセスのアンマネージ C++ 部分のパフォーマンスを妨げるかどうかです。

セーフ ポイントと GC ヘルパー メソッド (KeepAlive() など) の概念を調べ始めましたが、これやベンチマークに関する直接的な議論は見つかりませんでした。私がこれまでに理解していることから、安全なポイントの 1 つは、スレッドが管理されていないコードを実行している場合であり、この場合、ガベージ コレクションはクリーンアップを実行するためにスレッドを一時停止しませ(これは正しいですか?)。

私が抱えている主な質問は、これらの 2 種類のコードを同じプロセスで実行する場合と、別々のプロセスを実行する場合のネイティブ側でパフォーマンスの問題があることだと思います。

4

2 に答える 2

2

マネージ コードをまったく実行していないスレッドがある場合、.NET ガベージ コレクション中にそのスレッドがフリーズされることはありません。

マネージド コードを使用するスレッドが現在ネイティブ コードで実行されている場合、ガベージ コレクターはそのスレッドをフリーズせず、次にマネージド コードに到達したときにスレッドを停止するようにマークします。ただし、長時間戻らないネイティブ ディスパッチ ループを考えている場合は、ガベージ コレクターをブロックしている (または固定されたままにしておくと、GC が遅くなり断片化が発生する) ことに気付くかもしれません。そのため、ネイティブ コードで重要なタスクを実行するスレッドを完全に純粋な状態に保つことをお勧めします。

コンパイラが一部の標準 C++ コードの MSIL を暗黙的に生成していないことを確認する (それにより、マネージド コードとして実行する) ことは、少し注意が必要です。しかし、最終的には、 を注意深く使用することでこれを達成できます#pragma managed(push, off)

于 2013-02-21T18:02:47.713 に答える
2

混合モード アプリケーションを起動して実行するのは非常に簡単ですが、うまく動作させるのは非常に難しい場合があります。

その設計を選択する前に、慎重に検討することをお勧めします。特に、アプリケーションをどのように階層化するか、および管理されていないオブジェクトに期待する寿命の種類について検討してください。過去の経験からのいくつかの考え:

  1. C++ オブジェクトの有効期間 - アーキテクチャ別。
    C++ オブジェクトをローカル スコープで簡単に使用し、すぐに破棄します。当たり前のように聞こえますが、C++ オブジェクトは、アンマネージ リソースとして使用するように設計されたアンマネージ リソースです。通常、彼らは決定論的な作成と破棄を期待しており、多くの場合、RAII を広範囲に使用します。これをマネージ プログラムから制御するのは非常に厄介です。これを解決しようとする IDispose パターンが存在します。これは、存続期間の短いオブジェクトにはうまく機能しますが、存続期間の長いオブジェクトの場合はかなり面倒で、適切に処理するのは困難です。特に、関数スコープのみに存在するものではなく、マネージ クラスのアンマネージ オブジェクト メンバーを作成し始めると、すぐにプログラム内のすべてのクラスを IDisposable にする必要が生じ、突然マネージ プログラミングが ummanaged プログラミングよりも難しくなります。

  2. GC がアグレッシブすぎる。管理対象オブジェクトが範囲外になることについて話すとき、コードを読んでいる言語ではなく、IL コンパイラ/ランタイムの目で意味することを常に覚えておく価値があります。 ummanaged オブジェクトがメンバーおよび管理対象オブジェクトとして保持される場合物事が複雑になる可能性があるため、それを削除するように設計されています。破棄パターンがプログラムの上から下まで完全でない場合、GC はかなり積極的になる可能性があります。たとえば、ファイナライザーでアンマネージド オブジェクトを削除するマネージド クラスを作成しようとしたとします。マネージ オブジェクトで最後に行うことは、アンマネージ ポインターにアクセスしてメソッドを呼び出すことだとします。次に、GC は、その管理されていない呼び出し中に、管理対象オブジェクトを収集する絶好の機会であると判断する場合があります。突然、アンマネージ ポインターがメソッド呼び出しの途中で削除されます。

  3. GC は十分に積極的ではありません。アドレス制約内で作業している場合 (たとえば、32 ビット バージョンが必要な場合)、解放する必要があると判断しない限り、GC はメモリを保持することを覚えておく必要があります。これらの思考への唯一の入力は、管理された世界です。アンマネージド アロケーターがスペースを必要とする場合、GC への接続はありません。管理されていない割り当ては、GC が範囲外にあるオブジェクトを収集していないという理由だけで失敗する可能性があります。メモリ プレッシャ API がありますが、非常に単純な設計でのみ実際に使用可能/有用です。

  4. バッファコピー。また、大きなメモリ ブロックをどこに割り当てるかについても考慮する必要があります。マネージド ブロックは、アンマネージド ブロックのように固定できます。アンマネージド ブロックは、マネージド ブロックのように見せる必要がある場合にのみコピーできます。しかし、その大きなマネージド ブロックが実際に解放されるのはいつですか?

于 2013-02-21T19:03:59.580 に答える