SDL などの多くのライブラリには、プログラムを終了する直前にリソースを解放するチュートリアルのメソッド呼び出しがありますが、私の知る限り、ほとんどの OS は終了時にプロセスからすべてのメモリを解放します。とにかくアプリケーションが終了する場合はどうなりますか?
18 に答える
メモリとリソースは同じものではありません。
メモリは自動的に解放されます。
リソースは自動的にリリースされる場合とされない場合があります。
お使いの OS (すべてではありません) が終了時にメモリを解放する場合でも、いくつかの理由があります。
- それは良い方法です
- 対称性が追加されるため、コードの見栄えが良くなります
- OS は、デバイス (センサー、スキャナーなど) など、終了時に一部のリソースを自動的に解放しません。
- 誰かがこのコードを取得して、ランタイムのごく一部でのみライブラリを使用するプログラムに配置すると、不要なリソースは解放されます。
- 悪いメモリ リークを探している場合、デバッガはこれらの重要でないものを見つけられません。
プログラムに割り当てられたリソースが再利用されるかどうかは、オペレーティングシステムによって異なります。特に一部の組み込みシステムはリソースを解放しないことに注意してください。
ほとんどのオペレーティングシステムは、割り当てられたリソースを再利用して解放しますが、これをOSの動作に依存することはお勧めできません。したがって、プログラムを終了する前に、取得したすべてのリソースを解放する必要があります。
一般的に、私は他の人が言ったことに同意します。小さなことで良い習慣を実践しないと、大きなことでも失敗するでしょう. ただし、クラッシュのみのソフトウェアについて、(古い) ベルが鳴りました。
その概念は元の質問よりも「少し」拡張されていますが (OS リソースだけでなく、独自の (開いているファイルなど) も扱います)、それでも興味があるかもしれません。
基本的な考え方は、ソフトウェアがクラッシュに直面してユーザーデータなどを破壊してはならない場合 (データベースや tx ログなどを考えてください)、クリーンな出口パスを設計/プログラムする必要があるのはなぜですか。再起動する必要がある場合は、再実行してください。「クラッシュさせる」こともできます。
まあ、一日中その美徳について議論できると思いますが、それでも興味深いです.
自分で片付けるのは良い考えです。
1つには、リソースを解放すると、ファイル記述子/ネットワーク接続/共有メモリなどが制御された方法で整理されます。
次に、次のようなものを使用しているpurity
場合は、すべてのメモリが考慮されていることを確認できます。これにより、メモリ リークが発生していないというより良い感覚が得られます。
最初に言及すべきことは、すべてのリソースが同じではないということです。
これらの構造は (ほとんどの OS で) アプリケーションの終了時に自動的にクリーンアップされることはありません。
- 共有メモリ プール
- Win32 Mutex/Semaphore/Event/etc という名前。オブジェクト
- 特定の種類のソケット接続
- 独自のハードウェア デバイス ドライバーのデータ構造 (あいまい)
...そして、私はいくつかを忘れていると確信しています。
小規模では、アプリケーションがこれらのタイプのオブジェクトとコントロールを使用しているかどうかを簡単に知ることができます。ただし、大規模なアプリケーションでは、これらの特別な構造の 1 つ以上を割り当てる深く埋め込まれた (サード パーティの?) サブシステムを使用することは難しくありません。アプリケーションの残りの部分がふるいのように漏れる場合、困っているかもしれません。
アプリケーションが終了時にクリーンアップする必要があると言うのは、実際にはエンジニアリングの規律の問題です。今は必要ないかもしれませんが、後でアプリケーションが大きくなったときに感謝するかもしれません。
私が見る理由の1つは次のとおりです。
アプリケーションの終了時に、開発環境の出力ウィンドウにメモリリークがダンプされていると想定します。適切な方法で「クリーンアップ」しないと、「気にしない」ことから発生するすべてのリークから真のリークを検出する際に問題が発生します。
まず第一に、プロセスが終了したときにすべてのリソースが OS によって解放されるわけではありません。次に例を示します。
- ファイル - 開いたファイルを削除する必要がある場合があります。
- 名前付きリソース: 名前付きミューテックス、共有メモリなど。
- より複雑なアプリケーション レベルの状態の設定、統計情報など。
したがって、すべてのリソースを同じ方法で管理すれば、正しいことを行うことができます。
おっしゃる通り、最新のオペレーティング システムのほとんどは、アプリケーションの終了時にメモリやファイル ハンドルなどを解放します。したがって、私はあなたの意見に完全に同意し、アプリケーションが利用できるリソースが無制限である場合、リソースを解放する必要はありません。
実際のところ、リソースは無制限ではありません。実際にはまったく逆です。そのため、取得したものはすべて、システム上で実行されている別のアプリケーションでは取得できないものです。多くの場合、リソースはアプリの存続期間全体ではなく、その一部でのみ必要になります。そのため、システムの残りの部分とうまく連携し、必要なときに必要なものだけを取得する必要があります。
リソースを解放しないという慣行は、組み込みデバイスでは非常に一般的です。これらの場合、アプリケーションは実行されている唯一のものであり、終了することさえできず、唯一の方法はデバイスの電源を切ることです。私はそのようなシステムの 1 つを扱っており、組み込みデバイスにはリリースしないことによる問題はありませんが、私たちエンジニアはいくつかの理由でそれに悩まされています。
- 通常の PC で組み込みアプリケーションをテストする場合、シミュレートされたデバイスを開始および終了するプロセスとしてモデル化する必要があります。リソースが適切に解放された場合、シミュレートされたデバイスを開始および停止するテストを含む、1 つのプロセスで複数のテストを同じ実行で実行できます。
- ある時点で、組み込みコードの一部を取得し、実際のデバイスの機能のサブセットを実行する Windows/Linux 用のダイナミック リンク ライブラリとして公開する必要があるプロジェクトに取り組む必要がありましたが、実際のデバイスは必要ありませんでした。リソースの問題のため、ユーザーはこの DLL をアプリケーションに何度もロードおよびアンロードすることはできません。これは、そのたびに適切なメモリ チャンクが使用され、決して解放されないためです。これは制限事項として文書化されており、ライブラリを動的にロードするのではなく、ライブラリをアプリケーションにリンクするようにユーザーに依頼しています。残念なことに、この組み込みデバイスが開発されてから 10 年以上経つと、これらすべてのリソース割り当てを見つけて修正するのは非常に複雑になるため、私たちはそれを先延ばしにして、代わりに次善の製品を用意しています。
- 静的および動的コード分析ツールを使用して実際の欠陥を特定すると、大量の誤検知が発生するため、すべてのノイズの中で実際の欠陥を見逃す危険を冒さないように、それらを除外するツールを開発する必要がありました。
私のアドバイスは、OS が役に立たないかのようにコードを書くことです。それが、将来ソフトウェアを改善するための最も多くの選択肢を与えてくれるからです。
今日、ほとんどすべてのメインストリーム オペレーティング システムが、プログラムの終了時に、プログラムが割り当てたすべて (またはほとんど) のリソースを実際に解放することは、ほとんどの場合真実です。ただし、これはまずすべてのリソースに当てはまるわけではありません (たとえば、私の Mac では、プログラムの終了時に適切に閉じられていない場合、開いているソケットがしばらく開いたままになります)。
歴史的に、OS はまったく問題にならなかったため (特に古い 16 ビット OS の一部)、プログラミングの終了時にすべてのリソースをクリーンアップすることは、今もなお良いプログラミングの実践であり、自分のものをクリーンアップしないプログラマーは一般的に悪いプログラマーと見なされます。
これらはマナーです。
そして、あなたはあなたのプログラムを将来何度も何度も繰り返し実行される何かに変えたいかどうかを決して知りません。
とはいえ、これは必須ではなく、自分が何をしているのかを知っていれば、いつものようにルールを破ることができます。
オペレーティング システムは、システムの実行を維持するための最後の努力として、プロセスが終了した後もプロセスによって保持されているすべてのリソースを解放しようとします。アプリケーションは自分自身でクリーンアップすることになっていますが、OS の自動クリーンアップは、不適切に作成されたプログラムがメモリ リークやファイルの保持などによってシステム全体をダウンさせるのを防ぐように設計されています。シャットダウンする!理想的には、プロセスがシャットダウンした後に OS がクリーンアップする必要がないことが理想的です。ただし、実際には、一部のソフトウェアには間違いがあったり、単純に記述が不十分であり、OS がこれらの遅延プログラムをクリーンアップするのに役立つ機能です。
また、OS は一部のリソースをクリーンアップしません。ファイルをディスクに書き込んで、シャットダウン時に削除しようとしても、OS はそのファイルを自動的に削除しません (それがユーザーのドキュメントだったら?)。しかし、自分でクリーンアップしないと、プログラムは永久にディスク領域を「リーク」したことになります。ファイル以外の他の種類のリソースの例は他にもたくさんあります。
したがって、OS がクリーンアップすることを前提とする悪いソフトウェアを作成しないでください。おそらく 100% クリーンアップするわけではなく、そのメカニズムはくだらないソフトウェア専用です。代わりに良いソフトウェアを書きましょう!
Valgrindなどでメモリリークを見つけようとすると、出力がそれらのオブジェクトに関するレポートで溢れるため、アプリケーションのライフタイムに対応するライフタイムを持つオブジェクトでもメモリを解放する感覚はすぐにわかります。結局のところ、リークはまだリークです。
私はパーティーに遅れていることを知っていますが、ループ内のように実際のメモリリークが発生したとき以外の理由がない場合は、すべてのメモリとリソースを解放してください。最後に必要なのはあなたのゴミですメモリ プロファイラの出力が valgrind のように乱雑になります。
次に、メモリのクリーンアップは問題ではありません。スマート ポインターを使用すると、オーバーヘッドがほとんどまたはまったくなく、すべての作業が行われます。
最後に、これはライブラリの場合はさらに許しがたいことです。それが継続的なリーク (つまり、ガベージの 1 つ - 例: シングルトンの作成) でないかどうかは気にしません。ライブラリは、フリーストアにデータを残すべきではありません。
ご存じのように、OS によっては、プロセスが終了すると、メモリは通常 (うまくいけば!) 自動的に解放されます。
ただし、SDL などの多くのライブラリは、アプリケーションによって明示的に解放されない限り、システム リソースを割り当てるようにOSに要求します。
オペレーティング システムに優しく、クリーンアップするだけでなく、割り当てたメモリを解放することは、実行時間が不明なアプリケーションでは重要です。そのメモリは、他のアプリケーションが必要とするスペースを占有する可能性があるからです。
自分で後片付けをするのも良い習慣です。:)
他の回答が指摘しているように、リソースとメモリには違いがあります。私は Win32 API のコンテキストでのみ話すことができますが、同様の概念が SDL のようなライブラリに適用できると確信しています。リソースの自動解放を提供するライブラリもあれば、提供しないライブラリもあります。関係なくリソースを解放することは常に良い習慣です。デバイス固有のリソースは、解放されていない場合に問題を引き起こす可能性があるリソースの例です。リソース管理の詳細については、ライブラリのドキュメントを確認してください。
アプリケーションの終了時にメモリを解放する必要はありません。OS がメモリの再利用を処理します。他の人が述べたように、プリンターやファイルなどのリソースは、他のプログラムがアクセスできるようにロックを解除する必要があります。
たとえば、コードがメモリを解放せず (実行しても)、コード/プロジェクトのサイズが大きくなると、すべてのシステム メモリが消費され、メンテナンスで修正するのが難しくなります。したがって、将来のすべての目的のために、メモリを解放することをお勧めします。
新しいプロセスが開始されるたびに、メモリが割り当てられます。メモリには、次の 4 つのタイプがあります。
1.Heap
2.Local
3.Virtual
4.Global
これらのメイン変数は頻繁に使用されるため、一般に main() 変数のアドレスにローカルが使用されます。Global は、グローバル変数の記録を保持します。プログラムやプロセスにはヒープメモリが割り当てられ(ページが割り当てられ)、プログラムのデータや関数の情報が入っています。
OSがポインターの概念を使用すると、実際にはどうなりますか。また、プログラム内で 1 つのポインターが (何らかのコード エラーが原因で) 他のメモリを指し始め、前のメモリ位置を指すのを停止すると、最後のメモリ空間がヒープ メモリで使用されたままになります。しかし、このメモリ空間は役に立ちません。プログラムが終了すると、変数と関数の場所に従ってメモリが解放されます。しかし、私が言ったように、ポイントされていないメモリにはまだデータがありますが、誰もそれを指していないため、プログラムはそれを解放できません。
未使用のメモリ ロケーションを解放するには、free() を使用します。malloc、realloc、calloc、free はすべてヒープ メモリの機能です。free を呼び出すと、プログラムに割り当てられたページが削除され、未使用のメモリも解放されます。
In simple words,
プログラムに割り当てられた 50 ~ 100 のメモリ ロケーション。a と b (プログラム内の変数) は 60 と 70 を指しています。何らかのコード エラーが原因で、b は 60 を指し始めます。そのため、a と b の両方が 60 を指しています。現在、70 を指している人はいません。プログラムが exit を開始すると、a のメモリ位置を取得して解放します。次に、b のメモリ位置を取得して解放します。しかし、誰もそれを指していないため、プログラムは 70 の位置を知ることはありません。 70のメモリを解放しません。
一方、free() を呼び出すと、ページ全体が直接解放され、50 ~ 100 のメモリ ロケーション全体が解放されます。これで、指定されていないメモリ位置と指定されたメモリ位置の両方が自由に使用できるようになりました。
現在、言語には free() の機能を実行するためのガベージ コレクターがあります。しかし、OS について話すと、OS 自体がそれを行う必要があるため、ライブラリでは常に free が使用されます。また、コードを記述する最良の方法でもあります。