次のCコードがあるとします。
int main () {
int *p = malloc(10 * sizeof *p);
*p = 42;
return 0; //Exiting without freeing the allocated memory
}
そのCプログラムをコンパイルして実行するとき、つまりメモリにスペースを割り当てた後、アプリケーションを終了してプロセスが終了した後も、割り当てたメモリは割り当てられます(つまり、基本的にスペースを占有します)。
次のCコードがあるとします。
int main () {
int *p = malloc(10 * sizeof *p);
*p = 42;
return 0; //Exiting without freeing the allocated memory
}
そのCプログラムをコンパイルして実行するとき、つまりメモリにスペースを割り当てた後、アプリケーションを終了してプロセスが終了した後も、割り当てたメモリは割り当てられます(つまり、基本的にスペースを占有します)。
回答:
オペレーティングシステムによって異なります。最新の(そしてすべての主要な)オペレーティングシステムの大部分は、プログラムの終了時に解放されなかったメモリを解放します。
これに依存することは悪い習慣であり、明示的に解放することをお勧めします。問題は、コードの見た目が悪いだけではありません。小さなプログラムをより長く、実行時間の長いプログラムに統合したい場合があります。その後しばらくすると、メモリリークの追跡に何時間も費やす必要があります。
オペレーティングシステムの機能に依存すると、コードの移植性も低下します。
一般に、最新の汎用オペレーティングシステムは、プロセスの終了後にクリーンアップします。代替策は、システムが時間の経過とともにリソースを失い、プログラムが不十分であるか、リソースをリークするバグがほとんど発生しないために再起動が必要になるためです。
とにかくプログラムにリソースを明示的に解放させることは、次のようなさまざまな理由から良い習慣になることがあります。
ただし、メモリの解放をスキップする理由は次のとおりです。効率的なシャットダウン。たとえば、アプリケーションのメモリに大きなキャッシュがあるとします。終了時にキャッシュ構造全体を通過し、一度に1つずつ解放すると、それは有用な目的を果たさず、リソースを浪費します。特に、キャッシュを含むメモリページがオペレーティングシステムによってディスクにスワップされている場合を考慮してください。構造を歩いて解放することにより、それらのページすべてを一度にメモリに戻し、実際の利益のためにかなりの時間とエネルギーを浪費し、システム上の他のプログラムをスワップアウトさせることさえあります!
関連する例として、要求ごとにプロセスを作成し、完了時に終了させることで機能する高性能サーバーがあります。つまり、プロセスの最後にすべてがオペレーティングシステムの空きメモリに消えるので、メモリの割り当てを追跡する必要がなく、解放やガベージコレクションをまったく行う必要がありません。(同じ種類のことをカスタムメモリアロケータを使用してプロセス内で実行できますが、非常に注意深いプログラミングが必要です。基本的に、OSプロセス内で「軽量プロセス」という独自の概念を作成します。)
このスレッドへの最後の投稿から長い間投稿したことをお詫びします。
1つの追加ポイント。すべてのプログラムが正常に終了するわけではありません。クラッシュやctrl-Cなどにより、プログラムが制御されずに終了します。OSがヒープを解放しなかった、スタックをクリーンアップした、静的変数を削除しなかったなどの場合は、最終的にシステムをメモリリークまたはさらに悪い状態からクラッシュさせます。
これとは別に、Ubuntuでのクラッシュ/ブレーク、そして他のすべての最近のOSは、「処理された」リソースに問題があると思います。ソケット、ファイル、デバイスなどは、プログラムが終了/クラッシュしたときに「オープン」のままになることがあります。正常に終了する前のクリーンアップの一部として、「ハンドル」または「記述子」で何かを閉じることもお勧めします。
現在、ソケットを多用するプログラムを開発しています。ハングに陥ったときは、Ctrlキーを押しながらCキーを押してソケットを離します。std :: vectorを追加して、開いているすべてのソケットのリストを収集し、sigintとsigtermをキャッチするsigactionハンドラーを追加しました。ハンドラーはリストを調べ、ソケットを閉じます。スローの前に使用する同様のクリーンアップルーチンを作成して、途中で終了することを計画しています。
このデザインについてコメントしたい人はいますか?
ここで(最近のOSで)起こっていることは、プログラムが独自の「プロセス」内で実行されることです。これは、独自のアドレス空間、ファイル記述子などを備えたオペレーティングシステムエンティティです。malloc
呼び出しは、プロセスに割り当てられた「ヒープ」または未割り当てのメモリページからメモリを割り当てています。
この例のようにプログラムが終了すると、プロセスに割り当てられたすべてのリソースがオペレーティングシステムによって単にリサイクルまたは破棄されます。メモリの場合、割り当てられたすべてのメモリページは単に「空き」としてマークされ、他のプロセスで使用するためにリサイクルされます。ページは、mallocが処理するものよりも低レベルの概念です。その結果、malloc / freeの詳細はすべて、すべてがクリーンアップされるときに単純に洗い流されます。
これは道徳的に同等であり、ラップトップの使用が完了し、友人にそれを提供したい場合、各ファイルを個別に削除する必要はありません。ハードドライブをフォーマットするだけです。
他のすべての回答者が指摘しているように、これはすべてこれが当てはまることではありません。
はい。OSはリソースをクリーンアップします。まあ... NetWareの古いバージョンはしませんでした。
編集:San Jacintoが指摘したように、それを行わないシステム(NetWare以外)は確かにあります。使い捨てのプログラムでも、習慣を守るためにすべてのリソースを解放する習慣をつけます。
はい、プロセスが終了すると、オペレーティングシステムはすべてのメモリを解放します。
malloc
Cがメモリに対して行うことのみを約束できます。設計上、CはC自体の外部での動作に関してはほとんど何も保証しません。アプリが予期せず終了した場合、実行時のライブラリーは、生き残ることができなくなるため、作成されたランタイムライブラリはnullおよびvoidになります。
それは実際にはオペレーティングシステムに依存しますが、これまでに遭遇するすべてのオペレーティングシステムでは、プロセスが終了するとメモリ割り当てが消えます。
直接解放するのが一番だと思います。未定義の振る舞いは最悪のものです。そのため、プロセスでまだ定義されているときにアクセスできる場合は、それを実行してください。人々がそれに与えた多くの正当な理由があります。
W98でどこで、どのようにして見つけたかについては、本当の質問は「いつ」でしたか(これを強調する投稿を見ていませんでした)。小さなテンプレートプログラム(MIDI SysEx入力用で、さまざまなmallocされたスペースを使用)は、WndProcのWM_DESTROYビットのメモリを解放しますが、これをより大きなプログラムに移植すると、終了時にクラッシュしました。これは、大規模なクリーンアップ中にOSがすでに解放していたものを解放しようとしていることを意味すると思いました。私がWM_CLOSEでそれを実行し、次にDestroyWindow()を呼び出した場合、すべてが正常に機能し、即座にクリーン終了しました。
これはMIDIバッファとまったく同じではありませんが、プロセスをそのまま維持し、完全にクリーンアップしてから終了するのが最善であるという点で類似点があります。控えめなメモリチャンクでは、これは非常に高速です。多くの小さなバッファーは、少数の大きなバッファーよりも操作とクリーンアップで高速に動作することがわかりました。
誰かが大容量のメモリチャンクをディスク上のスワップファイルから持ち帰るのを避けるときに言ったように、例外が存在する可能性がありますが、それでも、割り当てられたスペースを増やして小さくすることで最小限に抑えることができます。