3

大まかに次のように構成された大規模なレガシーアプリケーションを継承しました。

class Application
{
    Foo* m_foo;
    Bar* m_bar;
    Baz* m_baz;

public:

    Foo* getFoo() { return m_foo; }
    Bar* getBar() { return m_bar; }
    Baz* getBaz() { return m_baz; }

    void Init()
    {
        m_foo = new Foo();
        m_bar = new Bar();
        m_baz = new Baz();

        // all of them are singletons, which can call each other
        // whenever they please
        // may have internal threads, open files, acquire
        // network resources, etc.
        SomeManager.Init(this);
        SomeOtherManager.Init(this);
        AnotherManager.Init(this);
        SomeManagerWrapper.Init(this);
        ManagerWrapperHelper.Init(this);
    }

    void Work()
    {
        SomeManagerWrapperHelperWhateverController.Start();

        // it will never finish
    }

    // no destructor, no cleanup
};

一度作成されたすべてのマネージャーは、アプリケーションの存続期間全体にわたってそこにとどまります。アプリケーションにはcloseまたはshutdownメソッドがなく、マネージャーにもそれらがありません。したがって、複雑な相互依存関係は処理されません。

問題は、オブジェクトの存続期間がアプリケーションの存続期間と緊密に結合している場合、クリーンアップをまったく行わないことは受け入れられている慣行ですか?オペレーティングシステム(この場合はWindows)は、プロセスが終了すると(タスクマネージャーで終了するか、ExitProcess、Abort、等。)?上記のアプローチで考えられる問題は何ですか?

または、より一般的な質問:グローバルオブジェクト(mainの外部で宣言されている)にはデストラクタが絶対に必要ですか?

4

5 に答える 5

3

クリーンアップをまったく行わないことは受け入れられている慣行ですか

それはあなたが誰に尋ねているかによります。

プロセスが終了すると、オペレーティングシステム(この場合はWindows)はすべて(スレッドを強制終了し、開いているファイルハンドル、ソケットなどを閉じる)をクリーンアップできますか?

はい、OSはすべてを取り戻します。メモリ、空きハンドルなどを要求します。

上記のアプローチで考えられる問題は何ですか

考えられる問題の1つは、メモリリーク検出器を使用すると、リークが常に表示されることです。

于 2012-08-17T07:17:35.697 に答える
3

オペレーティングシステム(この場合はWindows)は、プロセスが終了すると(タスクマネージャーで終了するか、ExitProcess、Abort、等。)?上記のアプローチで考えられる問題は何ですか?

オブジェクトがオペレーティングシステムによってクリーンアップされていないリソースを初期化していない限り、プロセスが終了するとOSがモップアップするため、明示的にクリーンアップするかどうかに関係なく、実際的な違いはありません。

ただし、オブジェクトOSによってクリーンアップされないリソースを作成している場合は、問題が発生しており、アプリのどこかにデストラクタまたはその他の明示的なクリーンアップコードが必要です。

これらのオブジェクトの1つが、データベースなどのリモートサービスでセッションを作成するかどうかを検討してください。もちろん、OSはこれが行われたことや、プロセスが停止したときにそれらをクリーンアップする方法を魔法のように認識しないため、これらのセッションは、何かがそれらを強制終了するまで開いたままになります(DBMS自体、おそらくタイムアウトしきい値などを適用することによって) 。アプリがリソースの小さなユーザーであり、大きなインフラストラクチャで実行されている場合はおそらく問題ではありませんが、アプリが十分なセッションを作成して孤立させた場合、そのリモートサービスでのリソースの競合が問題になり始める可能性があります。

オブジェクトの有効期間がアプリケーションの有効期間と緊密に結合している場合、クリーンアップをまったく行わないことは受け入れられていますか?

それは主観的な議論の問題です。私の個人的な好みは、明示的なクリーンアップコードを含め、私が作成する各オブジェクトを、実用的な場合はいつでも、それ自体の後でクリーンアップする責任を個人的に負うことです。アプリケーションの存続期間のオブジェクトがリファクタリングされて、オブジェクトの存続期間中は存続しなくなった場合、以前に省略したクリーンアップを追加する必要があるかどうかを確認する必要はありません。クリーンアップのために、私は一般的に、より実用的なYAGNIよりもRAIIに傾倒することを好むと言っていると思います。

于 2012-08-17T07:29:37.357 に答える
1

一般に、最新のオペレーティングシステムは、終了時にすべてのプロセスリソースをクリーンアップします。しかし、私の意見では、自分の後で片付けるのはまだ良いマナーです。(しかし、私はあなたがそれをしなければならなかったAmigaで「育てられた」のです。)

于 2012-08-17T07:19:05.993 に答える
1

仕様によって、または「周辺機器」の動作によって強制される場合があります。おそらく、アプリに大量のデータがバッファリングされていて、実際にディスクにフラッシュする必要があるか、DBが蓄積する可能性があります。「ハーフオープン」接続は明示的に閉じられていません。

それ以外は、@ cnicutarが言うように、それはあなたが誰に尋ねるかによります。私は次の理由で「気にしない」キャンプにしっかりと入っています。

1)必要のない追加のシャットダウンコードを記述せずに、とにかくアプリを動作させることは十分に困難です。

2)作成するコードが多いほど、バグが多くなり、テストを行う必要があります。このようなコードは、複数のOSバージョンでテストする必要がある場合があります:(

3)OS開発者は、システムの他の部分に全体的な影響を与えることなく、必要に応じて(たとえば、タスクマネージャーによって)アプリを常にシャットダウンできるようにするために長い時間を費やしてきました。OSにすでにいくつかの機能がある場合は、それを活用してみませんか?

4)スレッドは特定の問題を引き起こします-それらはどのような状態でもあり得ます。これらは、アプリのクローズを開始するスレッドとは異なるコアで実行されているか、システムコールでブロックされている可能性があります。OSがメモリを解放したり、ハンドルを閉じたりする前にすべてのスレッドが終了していることを確認するのは非常に簡単ですが、ユーザーコードから安全で信頼できる方法でそのようなスレッドを停止することは非常に困難です。

5)リークを検出する方法は、パフォーマンスを低下させるメモリマネージャだけではありません。大きなオブジェクト(ネットワークバッファーなど)がプールされている場合、アプリのクローズ時にリークレポートを発行するサードパーティのメモリマネージャーに依存することなく、実行時にリークがあるかどうかを簡単に判断できます。Valgrindのような集中的なメモリチェッカーは、実際には全体的なタイミングに影響を与えることでシステムの問題を引き起こします。

6)経験的に、明示的なシャットダウンコードがないWindows用に作成したすべてのアプリは、ユーザーが「赤い十字」の境界線アイコンをクリックするとすぐに完全に閉じます。これには、数千のクライアントが接続されたマルチコアボックスで実行されているビジーで複雑なIOCPサーバーが含まれます。

7)妥当なテストフェーズ(ロード/ソークテストを含むフェーズ)が実行されたと仮定すると、リークしているアプリと、クローズ時に使用しているメモリを解放しないことを選択したアプリを区別することは難しくありません。ザル-アプリは、メモリ/ハンドル/実行時間とともに常に増加するものを表示します。

8)明らかではない小さな、時折のリークは、膨大な時間を費やす価値がありません。ほとんどのWindowsボックスは、とにかく毎月再起動されます(火曜日のパッチ)。

9)不透明なライブラリは私のような開発者によって作成されることが多いため、とにかくシャットダウン時に偽の「リークレポート」が生成されます。

メモリをクリーンアップするためだけにシャットダウンコードを設計/書き込み/デバッグ/テストする-レポートは、私がなくてもできる高価な贅沢です:)

于 2012-08-17T08:04:35.113 に答える
0

オブジェクトごとに個別に決定する必要があります。オブジェクトがクリーンアップ時に特別なアクション(ディスクへのバッファーのフラッシュなど)を実行する必要がある場合、明示的に処理しない限り、これは発生しません。

于 2012-08-17T07:31:37.150 に答える