27

インスタンス/参照カウンターを使用しないシングルトン オブジェクトは、C++ でメモリ リークと見なす必要がありますか?

カウントがゼロのときにシングルトン インスタンスの明示的な削除を要求するカウンターがない場合、オブジェクトはどのように削除されるのでしょうか? アプリケーションの終了時に OS によってクリーンアップされますか? そのシングルトンがヒープにメモリを割り当てていたらどうなるでしょうか?

簡単に言うと、Singelton のデストラクタを呼び出す必要がありますか、それともアプリケーションの終了時にクリーンアップされることに依存できますか?

4

12 に答える 12

20

よくあることですが、「場合によります」。名前にふさわしいオペレーティング システムでは、プロセスが終了すると、プロセス内でローカルに使用されているすべてのメモリとその他のリソースが解放されます。あなたはそれについて心配する必要はありません。

ただし、シングルトンがそれ自体のプロセス (おそらくファイル、名前付きミューテックス、または同様のもの) の外部の有効期間を持つリソースを割り当てている場合は、適切なクリーンアップを検討する必要があります。

ここでRAIIがお手伝いします。次のようなシナリオがある場合:

class Tempfile
{
Tempfile() {}; // creates a temporary file 
virtual ~Tempfile(); // close AND DELETE the temporary file 
};

Tempfile &singleton()
{
  static Tempfile t;
  return t;
}

...その後、アプリケーションが終了しても、一時ファイルが閉じられて削除されることを安心できます。ただし、これはスレッドセーフではなく、オブジェクトの削除の順序が期待または要求と異なる場合があります。

ただし、シングルトンがこのように実装されている場合

Tempfile &singleton()
{
  static Tempfile *t = NULL;
  if (t == NULL)
    t = new Tempfile(); 
  return *t;
}

…では、状況が異なります。tempfile によって使用されるメモリは再利用されますが、デストラクタが呼び出されないため、ファイルは削除されません。

于 2008-11-08T10:50:20.660 に答える
14

オペレーティング システムによってクリーンアップされることを信頼できます。

とはいえ、デストラクタではなくファイナライザを使用するガベージ コレクション言語を使用している場合は、シングルトンを直接きれいにシャットダウンできる適切なシャットダウン手順が必要になる場合があります。アプリケーションを終了するだけで正しくクリーンアップできます。これは、ファイナライザーがほとんどの言語で一種の「ベスト エフォート」ベースで実行されるためです。一方、この種の信頼性を必要とするリソースはごくわずかです。ファイルハンドル、メモリなどはすべて、問題なく OS に戻ります。

ファイナライザではなく実際のデストラクタを使用して c++ のような言語で遅延割り当てされた (つまり、トリプル チェック ロック イディオムを使用して) シングルトンを使用している場合、プログラムのシャットダウン中にそのデストラクタが呼び出されることに依存することはできません。単一の静的インスタンスを使用している場合、デストラクタは main がある時点で完了した後に実行されます。

とにかく、プロセスが終了すると、すべてのメモリがオペレーティング システムに戻ります。

于 2008-11-07T21:47:00.163 に答える
11

すべてのオブジェクトを明示的にクリーンアップする必要があります。クリーンアップを OS に頼らないでください。

通常、シングルトンを使用して、ファイルやハードウェア リソースなどの制御をカプセル化します。その接続を適切にクリーンアップしないと、システム リソースが簡単にリークする可能性があります。リソースが前回の操作でロックされたままになっていると、次にアプリケーションを実行したときに失敗する可能性があります。もう 1 つの問題は、シングルトン インスタンスが所有するバッファーにバッファーがまだ存在する場合、バッファーのディスクへの書き込みなどのファイナライズが行われない可能性があることです。

これはメモリ リークの問題ではありません。問題は、メモリ以外のリソースをリークしている可能性があり、簡単に回復できない可能性があることです。

于 2008-11-07T22:07:32.087 に答える
9

プロセスの期間中、シングルトンが存在する傾向があるという@Aaron Fisherに同意しますが、言語と環境はそれぞれ異なります。

C++ の例では、典型的なシングルトン イディオムを使用します。

Singleton &get_singleton()
{
   static Singleton singleton;
   return singleton;
}

Singleton インスタンスは、関数が初めて呼び出されたときに構築され、同じインスタンスのデストラクタが、プログラムのシャットダウン時のグローバルな静的デストラクタ フェーズで呼び出されます。

于 2008-11-07T22:21:40.903 に答える
3

オブジェクトをどのように作成していますか?

グローバル変数または静的変数を使用している場合、プログラムが正常に終了すると仮定して、デストラクタが呼び出されます。

たとえば、プログラム

#include <iostream>

class Test
{
    const char *msg;

public:

    Test(const char *msg)
    : msg(msg)
    {}

    ~Test()
    {
        std::cout << "In destructor: " << msg << std::endl;
    }
};

Test globalTest("GlobalTest");

int main(int, char *argv[])
{
    static Test staticTest("StaticTest");

    return 0;
}

プリントアウト

In destructor: StaticTest 
In destructor: GlobalTest
于 2008-11-08T14:47:54.953 に答える
3

共有メモリ内のものを除き、あらゆる種類の割り当ては、プロセスの終了時にオペレーティング システムによって自動的にクリーンアップされます。したがって、シングルトン デストラクタを明示的に呼び出す必要はありません。というか漏れない

さらに、Meyers の Singleton のような典型的な singleton 実装は、最初の呼び出しでの初期化中にスレッドセーフであるだけでなく、アプリケーションが終了する (デストラクタが呼び出される) ときに正常に終了することが保証されています。

いずれにしても、アプリケーションに unix シグナル (つまり、SIGTERMまたはSIGHUP ) が送信された場合、デフォルトの動作は、静的に割り当てられたオブジェクト (シングルトン) のデストラクタを呼び出さずにプロセスを終了することです。これらのシグナルに関するこの問題を解決するには、exit を呼び出すハンドラを破棄するか、exit をそのようなハンドラとして破棄します --signal(SIGTERM,exit);

于 2008-11-07T21:48:10.053 に答える
2

アプリケーションが終了する前に、グローバルメモリ割り当てを明示的に解放するのは民間伝承です。私たちのほとんどは習慣からそれをしていると思います。構造を「忘れる」のはちょっと悪いと感じているからです。Cの世界では、割り当てにはどこかに割り当て解除が必要であるという対称性の法則があります。C ++プログラマーは、RAIIを知っていて実践している場合、考え方が異なります。

たとえばAmigaOSの古き良き時代には、実際のメモリリークがありました。メモリの割り当てを解除するのを忘れた場合、システムがリセットされるまで、メモリに再びアクセスできるようになることはありません。

最近、メモリリークがアプリケーションの仮想アドレス空間から忍び寄る可能性のある自尊心のあるデスクトップオペレーティングシステムを知りません。大容量のメモリ簿記がない場合、組み込みデバイスによってマイレージが異なる場合があります。

于 2008-11-08T15:06:29.910 に答える
1

シングルトンは、オブジェクトの1 つのインスタンスになります。これがカウンターを必要としない理由です。アプリケーションの長さにわたって存在する場合は、デフォルトのデストラクタで問題ありません。いずれの場合でも、プロセスが終了すると、メモリはオペレーティング システムによって再利用されます。

于 2008-11-07T21:45:55.173 に答える
1

リークの定義によって異なります。バインドされていないメモリの増加は、私の本のリークです。シングルトンはバインドされていません。参照カウントを提供しない場合は、意図的にインスタンスを存続させます。事故でも漏れでもない。

シングルトン ラッパーのデストラクタはインスタンスを削除する必要がありますが、これは自動ではありません。メモリを割り当てるだけで、OS リソースを割り当てない場合は意味がありません。

于 2008-11-07T21:49:00.597 に答える
0

プロセスによって割り当てられ、解放 (削除) されていないヒープ メモリは、OS によって回収されます。静的変数を使用するシングルトンの最も一般的な実装を使用している場合、これはアプリケーションの終了時にもクリーンアップされます。

*これは、新しいポインターを回避し、決してそれらをクリーンアップしないという意味ではありません。

于 2008-11-07T21:44:06.237 に答える