Cアプリケーションを終了すると、mallocされたメモリは自動的に解放されますか?


92

次のCコードがあるとします。

int main () {
  int *p = malloc(10 * sizeof *p);
  *p = 42;
  return 0;  //Exiting without freeing the allocated memory
}

そのCプログラムをコンパイルして実行するとき、つまりメモリにスペースを割り当てた後、アプリケーションを終了してプロセスが終了した後も、割り当てたメモリは割り当てられます(つまり、基本的にスペースを占有します)。


9
メモリをクリーンアップするのは「良いスタイル」です。保護されたメモリのないOSで実行する可能性があるため(以下の主な提案です)、メモリリークを発見する可能性が高くなり、あなたのコードは無駄のない正しいものです...
マットジョイナー

回答:


111

オペレーティングシステムによって異なります。最新の(そしてすべての主要な)オペレーティングシステムの大部分は、プログラムの終了時に解放されなかったメモリを解放します。

これに依存することは悪い習慣であり、明示的に解放することをお勧めします。問題は、コードの見た目が悪いだけではありません。小さなプログラムをより長く、実行時間の長いプログラムに統合したい場合があります。その後しばらくすると、メモリリークの追跡に何時間も費やす必要があります。
オペレーティングシステムの機能に依存すると、コードの移植性も低下します。


16
組み込みプラットフォームでwin98に出会ったことがあり、その経験に基づいて、プログラムを閉じてもメモリが解放されないと言えます。
2010

8
@ケンそれは一例でした。また、YAGNIとずさんなコーディングの間には線があります。リソースを解放しないと、それを超えてしまいます。YAGNIの原則は、プログラムを正しく機能させるコードではなく、機能に適用することも意図されていました。(そして、メモリを解放しないことはバグです)。
Yacoby、2010

5
+1:考慮すべき最も重要なことは、メモリ管理はYacobyが「オペレーティングシステムの機能」とかなり正確に述べていることです。私が誤解しない限り、プログラミング言語はプログラム実行の前後で何が起こるかを定義していません。
D.Shawley、2010

9
手動でメモリを解放すると、より多くの時間がかかり、より多くのコードが必要になり、バグの可能性が生じます(割り当て解除コードでバグを見たことがないことを教えてください!)。特定のユースケースであらゆる面でより悪いことを意図的に省略することは「ずさんな」ことではありません。プロセスの終了後にページを解放できない、またはそれをより大きなプログラム(YAGNI)に統合できないいくつかの古くて小さなシステムで実行するつもりでない限り、またはそれまでは、私にとっては純損失のように見えます。自分で片付けないことを考えるとプログラマーの自我が傷つくことは知っていますが、実際にはどのようにすればより良いのでしょうか?
ケン

6
SOでのメモリリークを提案している人は、すべての評判とバッジを削除する必要があります
Ulterior

53

一般に、最新の汎用オペレーティングシステムは、プロセスの終了後にクリーンアップします。代替策は、システムが時間の経過とともにリソースを失い、プログラムが不十分であるか、リソースをリークするバグがほとんど発生しないために再起動が必要になるためです。

とにかくプログラムにリソースを明示的に解放させることは、次のようなさまざまな理由から良い習慣なることがあります

  • 一時ファイルや外部リソースの状態の変更など、終了時にOSによってクリーンアップされない追加のリソースがある場合、終了時にそれらすべてを処理するためのコードが必要です。多くの場合、メモリの解放とエレガントに組み合わされます。
  • プログラムの寿命が長くなった場合、メモリを解放する唯一の方法は終了することではありません。たとえば、個々の作業単位に対する多くの要求を処理しながら実行を続けるサーバー(デーモン)にプログラムを変換したい場合や、プログラムが大きなプログラムの一部になる場合があります。

ただし、メモリの解放をスキップする理由は次のとおりです。効率的なシャットダウン。たとえば、アプリケーションのメモリに大きなキャッシュがあるとします。終了時にキャッシュ構造全体を通過し、一度に1つずつ解放すると、それは有用な目的を果たさず、リソースを浪費します。特に、キャッシュを含むメモリページがオペレーティングシステムによってディスクにスワップされている場合を考慮してください。構造を歩いて解放することにより、それらのページすべてを一度にメモリに戻し、実際の利益のためにかなりの時間とエネルギーを浪費し、システム上の他のプログラムをスワップアウトさせることさえあります!

関連する例として、要求ごとにプロセスを作成し、完了時に終了させることで機能する高性能サーバーがあります。つまり、プロセスの最後にすべてがオペレーティングシステムの空きメモリに消えるので、メモリの割り当てを追跡する必要がなく、解放やガベージコレクションをまったく行う必要がありません。(同じ種類のことをカスタムメモリアロケータを使用してプロセス内で実行できますが、非常に注意深いプログラミングが必要です。基本的に、OSプロセス内で「軽量プロセス」という独自の概念を作成します。)


11

このスレッドへの最後の投稿から長い間投稿したことをお詫びします。

1つの追加ポイント。すべてのプログラムが正常に終了するわけではありません。クラッシュやctrl-Cなどにより、プログラムが制御されずに終了します。OSがヒープを解放しなかった、スタックをクリーンアップした、静的変数を削除しなかったなどの場合は、最終的にシステムをメモリリークまたはさらに悪い状態からクラッシュさせます。

これとは別に、Ubuntuでのクラッシュ/ブレーク、そして他のすべての最近のOSは、「処理された」リソースに問題があると思います。ソケット、ファイル、デバイスなどは、プログラムが終了/クラッシュしたときに「オープン」のままになることがあります。正常に終了する前のクリーンアップの一部として、「ハンドル」または「記述子」で何かを閉じることもお勧めします。

現在、ソケットを多用するプログラムを開発しています。ハングに陥ったときは、Ctrlキーを押しながらCキーを押してソケットを離します。std :: vectorを追加して、開いているすべてのソケットのリストを収集し、sigintとsigtermをキャッチするsigactionハンドラーを追加しました。ハンドラーはリストを調べ、ソケットを閉じます。スローの前に使用する同様のクリーンアップルーチンを作成して、途中で終了することを計画しています。

このデザインについてコメントしたい人はいますか?


1
ソケットリソースを残しておくプログラムがあり、Ubuntuシステムは2週間ごとに再起動する必要があり、メモリが不足し始め、メモリが十分にあるため、これを言ってくれてうれしいです。クリーンアップを忘れた場合、システムリソースが破棄されるかどうかはわかりません。
タコグラブバス

8
Stackoverflowはフォーラムではありません。古い質問に答えることは何の問題もありませんmeta.stackexchange.com/questions/20524/reviving-old-questions
mk12

6

ここで(最近のOSで)起こっていることは、プログラムが独自の「プロセス」内で実行されることです。これは、独自のアドレス空間、ファイル記述子などを備えたオペレーティングシステムエンティティです。malloc呼び出しは、プロセスに割り当てられた「ヒープ」または未割り当てのメモリページからメモリを割り当てています。

この例のようにプログラムが終了すると、プロセスに割り当てられたすべてのリソースがオペレーティングシステムによって単にリサイクルまたは破棄されます。メモリの場合、割り当てられたすべてのメモリページは単に「空き」としてマークされ、他のプロセスで使用するためにリサイクルされます。ページは、mallocが処理するものよりも低レベルの概念です。その結果、malloc / freeの詳細はすべて、すべてがクリーンアップされるときに単純に洗い流されます。

これは道徳的に同等であり、ラップトップの使用が完了し、友人にそれを提供したい場合、各ファイルを個別に削除する必要はありません。ハードドライブをフォーマットするだけです。

他のすべての回答者が指摘しているように、これはすべてこれが当てはまることではありません。

  1. リソースを処理するために常にプログラミングをしている必要があります。Cではメモリも意味します。あなたはあなたのコードをライブラリに埋め込むことになるかもしれません、またはそれはあなたが期待するよりずっと長く走ることになるかもしれません。
  2. 一部のOS(古いOSと最新の組み込みOSの一部)は、このようなハードプロセスの境界を維持できず、割り当てが他のOSに影響を与える可能性があります。

4

はい。OSはリソースをクリーンアップします。まあ... NetWareの古いバージョンはしませんでした。

編集:San Jacintoが指摘したように、それを行わないシステム(NetWare以外)は確かにあります。使い捨てのプログラムでも、習慣を守るためにすべてのリソースを解放する習慣をつけます。


3
私は反対投票はしていませんが、これは後世のためのかなり危険な投稿です。DOSは依然として多くの組み込みプラットフォームで使用されており、メモリのクリーンアップを行うことを真剣に疑っています。広範な一般化は間違っています。
2010

@サンジャシント:それは良い点です。そのため、私はNetWareの参照を作成しましたが、おそらく明確化を使用することができます。少し編集します。
Mark Wilkins、

3
@San DOSはマルチタスクOSではありません-DOSプログラム(TSRを除く)が終了すると、次のプログラムをロードするためにすべてのメモリが使用可能になります。

@Neilはリマインダーに感謝しますが、組み込みシステムの一般的な使用法である、イベントが発生したときに起動するTSRのようなプログラムについて言及していました。それにもかかわらず、私が失敗した専門知識と明確化に感謝します:)
San Jacinto

2

はい、プロセスが終了すると、オペレーティングシステムはすべてのメモリを解放します。


これが反対投票された理由がわかりません。mallocされたメモリは、プロセスが死ぬと解放されます(mallocのウィキペディアの定義ではそうです)
Arve

7
ウィキペディアは、存在するすべてのOSのマニュアルではありません。 ほとんどの 現代のOSはメモリを再利用、すべてではない(特にないすべての古いもの)を行います。それに加えて、mallocCがメモリに対して行うことのみを約束できます。設計上、CはC自体の外部での動作に関してはほとんど何も保証しません。アプリが予期せず終了した場合、実行時のライブラリーは、生き残ることができなくなるため、作成されたランタイムライブラリはnullおよびvoidになります。
cHao

2

場合によっては、オペレーティングシステムによって通常はクリーンアップされますが、たとえば組み込みソフトウェアで作業している場合は、リリースされない可能性があります。

解放することを確認してください。後で大きなプロジェクトに統合するときに、時間を大幅に節約できます。


0

それは実際にはオペレーティングシステムに依存しますが、これまでに遭遇するすべてのオペレーティングシステムでは、プロセスが終了するとメモリ割り当てが消えます。


0

直接解放するのが一番だと思います。未定義の振る舞いは最悪のものです。そのため、プロセスでまだ定義されているときにアクセスできる場合は、それを実行してください。人々がそれに与えた多くの正当な理由があります。

W98でどこで、どのようにして見つけたかについては、本当の質問は「いつ」でしたか(これを強調する投稿を見ていませんでした)。小さなテンプレートプログラム(MIDI SysEx入力用で、さまざまなmallocされたスペースを使用)は、WndProcのWM_DESTROYビットのメモリを解放しますが、これをより大きなプログラムに移植すると、終了時にクラッシュしました。これは、大規模なクリーンアップ中にOSがすでに解放していたものを解放しようとしていることを意味すると思いました。私がWM_CLOSEでそれを実行し、次にDestroyWindow()を呼び出した場合、すべてが正常に機能し、即座にクリーン終了しました。

これはMIDIバッファとまったく同じではありませんが、プロセスをそのまま維持し、完全にクリーンアップしてから終了するのが最善であるという点で類似点があります。控えめなメモリチャンクでは、これは非常に高速です。多くの小さなバッファーは、少数の大きなバッファーよりも操作とクリーンアップで高速に動作することがわかりました。

誰かが大容量のメモリチャンクをディスク上のスワップファイルから持ち帰るのを避けるときに言ったように、例外が存在する可能性がありますが、それでも、割り当てられたスペースを増やして小さくすることで最小限に抑えることができます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.