mallocの後で解放しないと、本当に何が起こりますか?


538

これは、私を長年悩ませてきたものです。

私たちは皆、学校で教えられています(少なくとも、私はそうでした)、割り当てられているすべてのポインタを解放する必要があるということです。ただし、メモリを解放しない場合の実際のコストについては少し気になります。mallocループまたはスレッド実行の一部の中で呼び出された場合など、いくつかの明らかなケースでは、メモリリークがないように解放することが非常に重要です。ただし、次の2つの例を検討してください。

まず、次のようなコードがある場合:

int main()
{
    char *a = malloc(1024);
    /* Do some arbitrary stuff with 'a' (no alloc functions) */
    return 0;
}

ここで実際の結果は何ですか?私の考えでは、プロセスが終了してヒープ領域がなくなるため、呼び出しを逃しても害はありませんfree(ただし、閉鎖、保守性、および適切な運用のためにそれをとることの重要性は認識しています)。私はこの考えで正しいですか?

次に、少しシェルのように動作するプログラムがあるとします。ユーザーはのような変数を宣言できaaa = 123、それらは後で使用できるようにいくつかの動的データ構造に格納されます。明らかに、いくつかの* alloc関数(ハッシュマップ、リンクリストなど)を呼び出すソリューションを使用することは明らかです。この種のプログラムではmalloc、これらの変数はプログラムの実行中に常に存在している必要があり、静的に割り当てられたスペースでこれを実装するための良い方法(私が見ることができない)がないため、呼び出し後に解放しても意味がありません。割り当てられているがプロセス終了の一部としてのみ解放されている大量のメモリがあるのは悪い設計ですか?もしそうなら、代替は何ですか?


7
@NTDLS格付けシステムの魔法は実際に1度だけ機能します。6年経つと、「もっとふさわしい」答えが確かにトップに上がりました。
zxq9 2015

15
以下の人々は、最新の優れたOSはクリーンアップを行うと言い続けていますが、コードがカーネルモードで実行されている場合(たとえば、パフォーマンス上の理由から)はどうでしょうか。カーネルモードプログラム(Linuxなど)はサンドボックス化されていますか?そうでない場合は、abort()のような異常終了の前であっても、手動ですべてを解放する必要があると思います。
パーソンパーソンII

3
@ Dr.PersonPersonIIはい、カーネルモードで実行されるコードは通常、手動ですべてを解放する必要があります。
zwol 2016

1
free(a)実際にメモリを解放するために実際には何もしないことを付け加えたいと思います!これは、mallocのlibc実装の一部のポインターをリセットするだけです。これは、mmapの大きなメモリーページ(一般に「ヒープ」と呼ばれます)内の使用可能なメモリーチャンクを追跡します。そのページは、プログラムが終了するときにのみ解放され、前に解放されることはありません。
マルコボネーリ

1
Free()は、実際にメモリを解放する場合としない場合があります。ブロックを解放済みとしてマークし、後で再利用するか、ブロックを解放リストにリンクするだけです。それを隣接する空きブロックにマージするか、後続の割り当てのためにそれを残す場合があります。それはすべて実装の詳細です。
ジョーダンブラウン

回答:


378

ほぼすべての最新のオペレーティングシステムは、プログラムの終了後に割り当てられたすべてのメモリ領域を回復します。私が考えることができる唯一の例外は、プログラムの静的ストレージとランタイムメモリがほとんど同じであるPalm OSのようなものであり、解放しないとプログラムがより多くのストレージを占有する可能性があります。(ここでは推測しているだけです。)

したがって、一般的に、必要以上のストレージを持つことによる実行時のコストを除いて、問題はありません。あなたが与える例では確かに、それがクリアされるまで使用される可能性のある変数のメモリを保持したいとします。

ただし、メモリが不要になったらすぐに解放し、プログラムの終了時にまだ残っているものを解放することは、良いスタイルだと考えられています。これは、使用しているメモリを把握し、それがまだ必要かどうかを考えるための練習問題です。追跡しないと、メモリリークが発生する可能性があります。

一方、終了時にファイルを閉じるという同様の警告により、はるかに具体的な結果が得られます。そうしないと、書き込んだデータがフラッシュされない場合や、一時ファイルの場合はフラッシュされない場合があります。完了したら削除されます。また、データベースハンドルはトランザクションをコミットし、処理が終了したら閉じる必要があります。同様に、C ++やObjective Cなどのオブジェクト指向言語を使用している場合、オブジェクトを使い終わったときにオブジェクトを解放しないと、デストラクタが呼び出されず、クラスが担当するリソースがクリーンアップされない可能性があります。


16
だれもが最新のオペレーティングシステムを使用しているわけではないことを言及しておくのも良いでしょう。誰かがプログラムを取得した場合(メモリを回復しないOSでも実行される場合)、GGを実行します。
user105033 2009年

79
私はこの答えを本当に間違っていると考えています。ファイルハンドル/メモリ/ミューテックスであっても、リソースを使い終わった後は常にリソースの割り当てを解除する必要があります。その習慣があることで、サーバーを構築するときにそのような間違いを犯すことはありません。一部のサーバーは24時間365日稼働する予定です。これらの場合、何らかのリークは、サーバーが最終的にそのリソースを使い果たし、何らかの方法でハング/クラッシュすることを意味します。短いユーティリティプログラムです。リークはそれほど悪くありません。すべてのサーバー、すべてのリークは死です。自分でお願いします。自分の後片付け。それは良い習慣です。
EvilTeach 2009

120
「しかし、メモリが不要になったらすぐに解放し、プログラムの終了時にまだ残っているものを解放することは、良いスタイルだと考えられています。」あなたは間違っていると思いますか?
ポールトンブリン

24
プログラムが終了する瞬間まで必要なメモリストアがあり、プリミティブOSで実行していない場合、終了する直前にメモリを解放することはスタイル上の選択であり、欠陥ではありません。
Paul Tomblin、2010年

30
@Paul-EvilTeachに同意するだけでは、メモリを解放するのに適したスタイルとは見なされず、メモリを解放しないのは誤りです。あなたの言葉遣いは、これはあなたのネクタイに合ったハンカチを着ているのと同じくらい重要に思われます。実はパンツを履いているくらいです。
Heath Hunnicutt

110

はい、その通りです。この例は害を及ぼしません(少なくとも、ほとんどの最新のオペレーティングシステムでは)。プロセスによって割り当てられたすべてのメモリは、プロセスが終了するとオペレーティングシステムによって回復されます。

ソース:割り当てとGC神話(PostScriptアラート!)

割り当ての神話4:ガベージコレクションされていないプログラムは、割り当てられたすべてのメモリを常に割り当て解除する必要があります。

真実:頻繁に実行されるコードで割り当て解除が省略されると、リークが増大します。それらはめったに受け入れられません。しかし、プログラムが終了するまでほとんどの割り当てられたメモリを保持するプログラムは、多くの場合、割り振り解除を介在させずにパフォーマンスを向上させます。空きがない場合、Mallocの実装ははるかに簡単です。

ほとんどの場合、プログラムの終了直前にメモリの割り当てを解除しても意味がありません。 OSはとにかくそれを取り戻します。Freeは死んだオブジェクトに触れてページングします。OSはしません。

結果:割り当てをカウントする「リーク検出器」に注意してください。いくつかの「漏れ」は良いです!

とはいえ、すべてのメモリリークを回避するように心がけてください。

2番目の質問:あなたのデザインは大丈夫です。アプリケーションが終了するまで何かを保存する必要がある場合は、動的メモリ割り当てでこれを実行してもかまいません。必要なサイズが事前にわからない場合は、静的に割り当てられたメモリを使用できません。


3
私が読んだように、質問はリークしたメモリに実際に何が起こっているのかであり、この特定の例が大丈夫かどうかではありません。それでもまだ良い答えなので、私は反対票を投じません。
DevinB 2009年

3
おそらく(初期のWindows、初期のMac OS)存在していたと思われますが、終了する前にプロセスがメモリを解放してメモリを解放する必要があるOSです。
ピートカーカム

メモリの断片化やメモリ不足を気にしない限り、問題ありません。これを実行しすぎると、アプリケーションのパフォーマンスが失われます。難しい事実に加えて、常にベストプラクティスと適切な習慣の構築に従ってください。
NTDLS 2009年

1
私は現在-11に座っている受け入れられた答えを持っているので、彼は記録のために実行されていません。
ポールトンブリン

8
「リークディテクタのため」と言ってメモリを解放する必要性を説明するのは間違っていると思います。これは「警官がスピードカメラで待っているので、遊び道をゆっくり運転しなければならない」というようなものです。
セバスチャンマッハ

57

=== 今後の校正コードの再利用についてはどうですか?===

あなたがいる場合していないオブジェクトを解放するコードを記述しますが、閉じているプロセスによってfree'dされているメモリに依存することができたときに...つまり、小さな1回の使用を、そしてあなただけ使用しても安全であることにコードを制限していますプロジェクトまたは「使い捨て」[1]プロジェクト)...プロセスがいつ終了するかがわかります。

あなたは場合)(自由はすべてのあなたの動的に割り当てられたメモリよ、あなたは将来、コードを校正し、他の人が大きなプロジェクトでそれを使わせているというコードを記述します。


[1]「使い捨て」プロジェクトについて。「捨てる」プロジェクトで使用されるコードには、捨てられない方法があります。次に、10年が経過し、「使い捨て」コードがまだ使用されていることがわかります。

ハードウェアをよりよく機能させるために、単に楽しみのためにコードを書いた人の話を聞きました。彼は「ただの趣味であり、大きく専門的ではない」と言った。数年後、多くの人々が彼の「趣味」のコードを使用しています。


8
「小規模プロジェクト」に反対票を投じました。ターゲットプラットフォームを知っていると時間の無駄になるため、非常に意図的に終了時にメモリを解放しない大規模なプロジェクトがたくさんあります。IMO、より正確な例は「孤立したプロジェクト」でしょう。たとえば、他のアプリケーションに含まれる再利用可能なライブラリを作成している場合、明確に定義された出口点がないため、メモリをリークすることはありません。スタンドアロンアプリケーションの場合、いつプロセスが終了するかを常に正確に把握し、クリーンアップをOSにオフロードすることを意識して決定できます(どちらの方法でもチェックを実行する必要があります)。
Dan Bechard 2017

昨日のアプリケーションは今日のライブラリー関数であり、明日は何千回も呼び出す長命のサーバーにリンクされます。
エイドリアン・マッカーシー

1
@AdrianMcCarthy:関数が静的ポインターがnullであるかどうかをチェックし、それがnullであるmalloc()場合はそれを初期化し、ポインターがまだnullの場合は終了する場合、そのような関数は、free呼び出されない場合でも任意の回数安全に使用できます。無制限の量のストレージを使い果たしてしまうメモリリークと、有限で予測可能な量のストレージしか無駄にできない状況を区別することは、おそらく価値があると思います。
スーパーキャット2018

@supercat:私のコメントはコードが時間とともに変化することについて話していました。もちろん、限られた量のメモリをリークすることは問題ではありません。しかし、いつの日か、誰かがその関数を変更して、静的ポインタを使用しないようにするつもりです。コードが指すメモリを解放するための準備がない場合、それはハードな変更になります(または、さらに悪いことに、変更は悪くなり、無限のリークが発生します)。
エイドリアンマッカーシー

1
@AdrianMcCarthy:静的ポインターを使用しないようにコードを変更するには、ポインターをある種の「コンテキスト」オブジェクトに移動し、そのようなオブジェクトを作成および破棄するコードを追加する必要があります。null割り当てが存在しない場合は常にポインターがあり、割り当てが存在する場合はnullでない場合、特に割り当てが解放され、nullコンテキストが破棄されたときにポインターを設定することは、特に実行する必要がある他のすべてのものと比較すると簡単です。静的オブジェクトをコンテキスト構造に移動します。
スーパーキャット2018

52

あなたは正しいです、害はありません、それは単に終了する方が速いです

これにはさまざまな理由があります。

  • すべてのデスクトップおよびサーバー環境は、exit()でメモリ空間全体を解放するだけです。それらは、ヒープなどのプログラム内部のデータ構造を認識していません。

  • とにかく、ほとんどすべてのfree()実装メモリをオペレーティングシステムに返すことはありません。

  • さらに重要なことに、exit()の直前に実行すると時間の無駄になります。終了時に、メモリページとスワップ領域が解放されます。対照的に、一連のfree()呼び出しはCPU時間を消費し、ディスクページング操作、キャッシュミス、キャッシュエビクションを引き起こす可能性があります。

possiblility justifingリユース将来コードの確実性を考慮しますが、それは間違いなくありません:無意味なOPSのをアジャイルの方法。YAGNI!


2
私はかつて、プログラムのメモリ使用量を理解するために短い時間を費やしたプロジェクトに取り組みました(サポートする必要があり、作成しませんでした)。経験に基づいて、私は逸話的に2番目の弾丸に同意します。ただし、あなた(または誰か)がこれが真実であるというより多くの証拠を提供してほしいと思います。
user106740 2009

3
気にしないで、答えを見つけました: stackoverflow.com/questions/1421491/…。どうもありがとう!
user106740 2009

YAGNIと呼ばれる@aviggiano。
v.oddou 2016年

YAGNIの原則は両方の方法で機能します。シャットダウンパスを最適化する必要はありません。時期尚早の最適化など。
エイドリアン・マッカーシー

26

OPが正しい、または害がないと言う人にはまったく同意しません。

誰もが最新および/またはレガシーOSについて話している。

しかし、OSがまったくない環境にいる場合はどうなりますか?何もないところは?

今、あなたはスレッドスタイルの割り込みを使用していて、メモリを割り当てていると想像してください。C標準では、ISO / IEC:9899は次のように表されるメモリの寿命です。

7.20.3メモリ管理関数

1 calloc、malloc、およびrealloc関数の連続呼び出しによって割り当てられるストレージの順序と連続性は指定されていません。割り当てが成功した場合に返されるポインターは、任意のタイプのオブジェクトへのポインターに割り当てられ、割り当てられたスペース内のそのようなオブジェクトまたはそのようなオブジェクトの配列にアクセスできるように適切に調整されます(スペースが明示的に割り当て解除されるまで) 。割り当てられたオブジェクトの有効期間は、割り当てから割り当て解除までです。[...]

したがって、環境があなたのために解放の仕事をしているとは言えません。それ以外の場合は、「またはプログラムが終了するまで」という最後の文に追加されます。

言い換えれば、メモリを解放しないことは単に悪い習慣ではありません。移植性がなく、C準拠のコードではありません。少なくとも「次の場合、正しいと見なすことができます:[...]、環境によってサポートされています」。

しかし、OSがまったくない場合、誰もあなたのために仕事をしていません(組み込みシステムではメモリを割り当てたり再割り当てしたりしないのが普通ですが、場合によってはそうしたいこともあります。)

つまり、一般的にプレーンなC(OPがタグ付けされている)と言えば、これは単にエラーが発生し、移植性のないコードを生成するだけです。


4
反対の議論は、もしあなたが組み込み環境なら、あなたは-開発者として-そもそもあなたのメモリ管理においてはるかに注意深いであろうということです。通常、これは、実行時のmallocs / reallocsをまったく用意するのではなく、実際に静的固定メモリを事前に事前に割り当てることを目的としています。
John Go-Soco

1
@lunarplasma:あなたが言っていることが正しくないわけではありませんが、それは言語標準が述べていることを変更するものではありません。「気にしなくていい」という人もいれば大丈夫なケースが多いので理解できます。しかし、なぜ彼が気にする必要がないのかを少なくとも知っておくべきです。質問がその特別なケースに関連しない限り、特に省略しないでください。そして、OPは一般的に理論(学校)の観点からCについて質問しているため 「必要ない」と言っても大丈夫です!
dhein

2
OSがないほとんどの環境では、プログラムが「終了」できる手段はありません。
スーパーキャット2016年

@supercat:私が以前に書いたように:あなたはそれについて正しいです。しかし、教育の理由や学校の側面について誰かがそれについて質問している場合、「ほとんどの場合、それは重要ではないので、それについて考える必要はありません」と言うのは適切ではありません。定義は理由のために与えられており、ほとんどの環境がそれを処理するからといって、気にする必要がないとは言えません。それが私のポイントです。
dhein

2
C標準を引用する場合は-1、ほとんどの場合はオペレーティングシステムがない場合は適用されません。特にメモリ管理と標準ライブラリ関数(これも明らかに存在しない)に関する標準の義務を備えた機能を提供するランタイムがないためです。ランタイム/ OSとともに)。

23

通常、割り当てられたすべてのブロックを解放します。今日、私のプログラムのエントリポイントはかもしれませんがmain(int argc, char *argv[])、明日はそれがfoo_entry_point(char **args, struct foo *f)関数ポインタとして型付けされるかもしれません。

それで、それが起こった場合、私は今リークを持っています。

2番目の質問に関しては、私のプログラムがa = 5のような入力を受け取った場合、aにスペースを割り当てるか、後続のa = "foo"に同じスペースを再割り当てします。これは次の状態になるまで割り当てられたままになります:

  1. ユーザーが「unset a」と入力した
  2. 信号を処理するか、ユーザーが「終了」と入力して、私のクリーンアップ機能に入りました

プロセスの終了後にメモリを解放しない最新の OS は考えられません。次に、free()は安価です。クリーンアップしてみませんか?他の人が言ったように、valgrindのようなツールは、本当に心配する必要があるリークを見つけるのに最適です。例のブロックには「まだ到達可能」というラベルが付いていますが、リークがないことを確認しようとすると、出力にノイズが追加されるだけです。

別の神話は、「もしmain()の場合、解放する必要がない」ということですが、これは誤りです。以下を検討してください。

char *t;

for (i=0; i < 255; i++) {
    t = strdup(foo->name);
    let_strtok_eat_away_at(t);
}

それがフォーク/デーモン化の前に行われた場合(そして理論的には永久に実行されている場合)、プログラムは未確定のサイズt 255をリークしました。

優れた、よく書かれたプログラムは、常にそれ自体をクリーンアップする必要があります。すべてのメモリを解放し、すべてのファイルをフラッシュし、すべての記述子を閉じ、すべての一時ファイルをリンク解除します。このクリーンアップ機能は、正常に終了したとき、またはさまざまな種類の致命的なシグナルを受け取ったときに到達します。クラッシュを検出して再開します。

本当に、あなたが他のものに移るときにあなたのものを維持しなければならない貧しい魂に親切にしてください..それらにそれらを「valgrind clean」に渡してください:)


1
そして、はい、私はかつてチームメイトに「main()でfree()を呼び出す必要はない」と言っていました。<shudders>
Tim Post

free() is cheap1つずつ解放する必要がある複雑な関係を持つ10億のデータ構造がある場合を除いて、データ構造をトラバースしてすべてを解放しようとすると、特にそのデータ構造の半分がすでにページアウトされている場合、シャットダウン時間が大幅に増加する可能性があります。ディスクには、何の利点もありません。
Lie Ryan

3
@LieRyan 10億の場合、文字通り 10億の構造のように、特別な配慮が必要な他の問題が最も明確にあります。この特定の回答の範囲をはるかに超えています:)
Tim Post

13

終了するときにメモリを解放しないでおくのはまったく問題ありません。malloc()は、「ヒープ」と呼ばれるメモリ領域からメモリを割り当てます。プロセスが終了すると、プロセスの完全なヒープが解放されます。

そうは言っても、終了する前にすべてを解放するのが良いと人々が依然として主張する1つの理由は、メモリデバッガー(Linuxのvalgrindなど)が解放されていないブロックをメモリリークとして検出し、さらに「実際の」メモリリークがあると、最後に「偽の」結果が出た場合、それらを見つけるのはより困難になります。


1
Valgrindは、「リーク」と「まだ到達可能」を区別するかなり良い仕事をしていませんか?
Christoffer

11
「完全に細かい」の場合は-1割り当てられたメモリを解放せずにそのままにしておくのは不適切なコーディング方法です。そのコードがライブラリに抽出された場合、その場所全体にmemleaksが発生します。
DevinB 2009年

5
+1して補正します。compieの回答を参照してください。有害freeであるexitと見なされたとき。
R .. GitHub ICE HELPING ICE STOP 2012

11

割り当てたメモリを使用している場合は、問題はありません。メモリを解放せずに、またプログラムの残りの部分で利用できるようにすることなくメモリを割り当てる関数(main以外)を作成すると、問題になります。その後、メモリは割り当てられた状態で実行を続けますが、使用する方法はありません。プログラムや他の実行中のプログラムからそのメモリが奪われます。

編集:他の実行中のプログラムがそのメモリを奪われていると言うのは100%正確ではありません。オペレーティングシステムでは、プログラムを仮想メモリ(</handwaving>)にスワップアウトする代わりに、常に使用を許可できます。ただし、重要なのは、プログラムが使用していないメモリを解放すると、仮想メモリのスワップが必要になる可能性が低くなることです。


11

このコードは通常は問題なく機能しますが、コードの再利用の問題を考慮してください。

割り当てられたメモリを解放しないコードスニペットを作成した可能性があります。これは、メモリが自動的に再利用されるような方法で実行されます。大丈夫そうです。

次に、誰かがスニペットをプロジェクトにコピーし、毎秒1000回実行されます。その人は今彼のプログラムで巨大なメモリリークを持っています。一般にあまりよくありません。通常、サーバーアプリケーションにとって致命的です。

企業ではコードの再利用が一般的です。通常、会社は従業員が作成したすべてのコードを所有し、すべての部門は会社が所有するものは何でも再利用できます。したがって、そのような「無邪気に見える」コードを書くことにより、他の人々に潜在的な頭痛の種を引き起こします。これはあなたを解雇するかもしれません。


2
誰かがスニペットをコピーする可能性だけでなく、修正されて繰り返し実行されるように変更された特定のアクションを実行するように作成されたプログラムの可能性にも注目する価値があります。このような場合、メモリを一度割り当ててから解放せずに繰り返し使用しても問題ありませんが、(解放せずに)すべてのアクションにメモリを割り当てて放棄するのは悲惨です。
スーパーキャット2014年

7

ここで実際の結果は何ですか?

プログラムがメモリをリークしました。お使いのOSに応じて復旧している場合があります。

最新のデスクトップオペレーティングシステム、プロセスの終了時にリークしたメモリを回復するため、悲しいことに、問題を無視するのが一般的です。

しかし、あなたは、あなたがに頼るべきではありません安全機能に依存している、とあなたのプログラム(または関数)は、この動作は、システム上で実行するかもしれない、「ハード」メモリリーク、で結果を次の時間。

カーネルモード、またはメモリ保護をトレードオフとして採用していないヴィンテージ/組み込みオペレーティングシステムで実行している可能性があります。(MMUはダイスペースを占有し、メモリ保護は追加のCPUサイクルを要し、プログラマーに自分自身のクリーンアップを依頼するのはそれほど多くありません)

メモリは好きなように使用および再利用できますが、終了する前にすべてのリソースの割り当てを解除したことを確認してください。


5

実際、OSTEPオンラインテキストブックには、オペレーティングシステムの学部課程のセクションがあり、あなたの質問を正確に説明しています。

関連するセクションは、6ページのメモリAPIの章の「メモリを解放すること」であり、次の説明があります。

場合によっては、free()を呼び出さないことが理にかなっているように見えることがあります。たとえば、プログラムの寿命は短く、すぐに終了します。この場合、プロセスが停止すると、OSは割り当てられたすべてのページをクリーンアップするため、メモリリーク自体は発生しません。これは確かに「上手くいく」(7ページの余白を参照)一方で、開発するのはおそらく悪い習慣であるため、そのような戦略の選択には注意が必要です。

この抜粋は、仮想メモリの概念の導入に関連しています。基本的に本のこの時点で、著者はオペレーティングシステムの目標の1つは「メモリの仮想化」、つまりすべてのプログラムが非常に大きなメモリアドレス空間にアクセスできると信じ込ませることであると説明しています。

舞台裏では、オペレーティングシステムは、ユーザーに表示される「仮想アドレス」を物理メモリを指す実際のアドレスに変換します。

ただし、物理メモリなどのリソースを共有するには、オペレーティングシステムがそれを使用しているプロセスを追跡する必要があります。したがって、プロセスが終了した場合、そのプロセスのメモリを再利用して他のプロセスとメモリを再分配および共有できるようにするのは、オペレーティングシステムの機能と設計目標の範囲内です。


編集:抜粋で言及された余談は以下にコピーされます。

サイド:プロセスの終了時にメモリがリークされない理由

存続期間の短いプログラムを作成する場合、を使用してスペースを割り当てる場合がありますmalloc()。プログラムが実行されて完了しようとしfree()ています。終了する直前に何度も呼び出す必要がありますか?それは間違いではないように思われますが、いかなる意味においてもメモリが「失われる」ことはありません。その理由は単純です。システムには、実際には2つのレベルのメモリ管理があります。メモリ管理の最初のレベルはOSによって実行されます。OSは、実行時にメモリをプロセスに渡し、プロセスが終了(または終了)したときにメモリを取り戻します。2番目のレベルの管理は各プロセス内にあります。たとえば、呼び出し時のヒープ内です。 malloc()free()。および。電話に出られなくてもfree()(したがって、ヒープ内のメモリをリークします)、プログラムの実行が終了すると、オペレーティングシステムはプロセスのすべてのメモリ(コード、スタック、および関連するヒープのページを含む)を再利用します。アドレス空間のヒープの状態に関係なく、OSはプロセスが終了したときにそれらのページをすべて取り戻すため、解放しなかったにもかかわらずメモリが失われることはありません。

したがって、存続期間の短いプログラムの場合、メモリーのリークが原因で操作上の問題が発生することはほとんどありません(ただし、形式が悪いと見なされる場合があります)。長時間実行されるサーバー(Webサーバーやデータベース管理システムなど、決して終了しない)を作成する場合、メモリのリークははるかに大きな問題であり、アプリケーションがメモリ不足になると、最終的にはクラッシュにつながります。そしてもちろん、メモリリークは、特定のプログラム(オペレーティングシステム自体)内ではさらに大きな問題です。もう一度見せてください:カーネルコードを書く人はすべての中で最も難しい仕事をしています...

Memory APIの章の7ページから

オペレーティングシステム:3つの簡単なピース
Remzi H. Arpaci-DusseauおよびAndrea C. Arpaci-Dusseau Arpaci-Dusseau Books 2015年3月(バージョン0.90)


4

変数を解放しなくても本当の危険はありませんが、最初のブロックを解放せずにメモリブロックへのポインタを別のメモリブロックに割り当てると、最初のブロックはアクセスできなくなりますが、領域を占有します。これはメモリリークと呼ばれるものであり、これを定期的に行うと、プロセスはますます多くのメモリを消費し始め、他のプロセスからシステムリソースを奪います。

プロセスが短命である場合、割り当てられたすべてのメモリがプロセスの完了時にオペレーティングシステムによって解放されるため、これをやめることがよくありますが、それ以上使用する必要のないすべてのメモリを解放する習慣をつけることをお勧めします。


1
「危険はありません」という最初のステートメントで-1と言いたいのですが、なぜ危険があるのか​​について思慮深い答えを出します。
DevinB 2009年

2
危険が進むにつれ、それはかなり無害です。私は、segfaultを介していつでもメモリリークを実行します。
Kyle Cronin

1
非常に真実であり、私たち2人とも= Dを好まない
DevinB 2009年

2
@KyleCronin私は考え多くの両方が重大なバグやセグメンテーション違反しているためではなく、メモリリークよりもセグメンテーション違反を持って検出するのが容易です。メモリリークは、「かなり無害」であるため、気付かれず、解決されないことがよくあります。私のRAMと私は心から反対します。
Dan Bechard

@ダン開発者として、確かに。ユーザーとして、メモリリークを取り上げます。メモリリークはあるものの、動作しないソフトウェアよりも、動作するソフトウェアが欲しいです。
Kyle Cronin

3

あなたはその点で完全に正しいです。プログラムが終了するまで変数が存在しなければならない小さな自明なプログラムでは、メモリの割り当てを解除しても実際にはメリットはありません。

実際、私はかつて、プログラムの各実行が非常に複雑であるが比較的短期間であるプロジェクトに関与していたため、メモリの割り当てを維持し、割り当てを誤って解除してプロジェクトを不安定にすることはありませんでした。

そうは言っても、ほとんどのプログラムでは、これは実際にはオプションではありません。または、メモリ不足になる可能性があります。


2

あなたが正しい、プロセスが終了するとメモリが自動的に解放されます。プロセスが終了すると、オペレーティングシステムにすべて放棄されるので、大規模なクリーンアップを行わないように努力する人もいます。ただし、プログラムの実行中は、未使用のメモリを解放する必要があります。そうしないと、ワーキングセットが大きくなりすぎると、最終的に不足するか、過度のページングが発生する可能性があります。


2

アプリケーションをゼロから開発している場合は、無料でいつ電話をかけるかについて、知識に基づいた選択を行うことができます。あなたのサンプルプログラムは問題ありません:それはメモリを割り当て、おそらくあなたはそれを数秒間動かしてから閉じて、要求したすべてのリソースを解放します

ただし、他の何か(サーバー/長時間実行アプリケーション、または他の誰かが使用するライブラリ)を作成している場合は、mallocを実行するたびにfreeを呼び出すことを期待する必要があります。

実用的な側面を少しの間無視して、より厳密なアプローチに従い、mallocをすべて解放するように強制する方がはるかに安全です。コーディングするたびにメモリリークを監視する習慣がない場合は、簡単にいくつかのリークが発生する可能性があります。つまり、言い換えれば、それなしで逃げることができます。ただし注意してください。


0

プログラムが終了する前に数メガバイトを解放するのを忘れると、オペレーティングシステムはそれらを解放します。しかし、プログラムが一度に数週間実行され、プログラム内のループが各反復で数バイトを解放するのを忘れた場合、通常の方法で再起動しない限り、コンピューターで使用可能なすべてのメモリを使い果たしてしまう強力なメモリリークが発生します。基本=>たとえプログラムがもともと設計されていなかったとしても、プログラムが非常に大きなタスクに使用されている場合、小さなメモリリークであっても悪い可能性があります。


-2

あなたの2つの例は実際には1つだけだと思いますfree()。これはプロセスの最後にのみ発生するはずです。指摘したように、プロセスは終了しているので役に立たないのです。

ただし、2番目の例では、唯一の違いは、未定義の数を許可することですmalloc()。これにより、メモリが不足する可能性があります。この状況を処理する唯一の方法は、戻りコードを確認し、malloc()それに応じて行動することです。

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