238

CまたはC++アプリケーションでメモリリークが発生することは許容されますか?

メモリを割り当てて、アプリケーションのコードの最後の行(たとえば、グローバルオブジェクトのデストラクタ)まで使用するとどうなりますか?メモリ消費量が時間の経過とともに増加しない限り、アプリケーションの終了時にOSを信頼してメモリを解放しても大丈夫ですか(Windows、Mac、およびLinuxの場合)。OSによってメモリが解放されるまでメモリが継続的に使用されていた場合、これを実際のメモリリークと見なすことさえできますか。

サードパーティの図書館があなたにこの状況を強制した場合はどうなりますか?それがなければどんなに素晴らしいかもしれないとしても、そのサードパーティのライブラリを使用することを拒否しますか?

実用上の欠点は1つだけです。それは、これらの良性のリークがメモリリーク検出ツールで誤検知として表示されることです。

4

50 に答える 50

337

いいえ。

専門家として、私たちが自分自身に尋ねるべきではない質問は、「これをやっても大丈夫ですか?」ということです。むしろ「これを行う正当な理由はありますか?」また、「メモリ リークを突き止めるのが面倒」というのは正当な理由ではありません。

私は物事をシンプルに保つのが好きです。そして、簡単なルールは、プログラムにメモリ リークがあってはならないということです。

それは私の人生もシンプルにします。メモリ リークを検出した場合は、精巧なデシジョン ツリー構造を調べて「許容できる」メモリ リークかどうかを判断するのではなく、それを排除します。

これは、コンパイラの警告に似ています。この警告は、特定のアプリケーションにとって致命的ですか? そうでないかもしれない。

しかし、最終的にはプロの規律の問題です。コンパイラの警告を許容し、メモリ リークを許容することは悪い習慣であり、最終的には私を苦しめることになります。

極端に言えば、外科医が手術器具の一部を患者の体内に残すことは許されるでしょうか?

SurgeonOverflow.com に投稿されたこの質問を見た場合、その機器を取り外すコスト/リスクが、そのままにしておくコスト/リスクを超える状況が発生する可能性があります。 「いいえ」以外の答えを見た場合、医療専門家に対する私の信頼が著しく損なわれることになります.

–</p>

サードパーティのライブラリが私にこのような状況を強いた場合、問題のライブラリの全体的な品質を真剣に疑うようになります. 車を試乗して、カップホルダーの 1 つにワッシャーとナットが緩んでいるのを見つけたようなものです。それ自体は大した問題ではないかもしれませんが、品質へのコミットメントの欠如を表しているので、代替案を検討します。

于 2008-11-07T19:20:25.530 に答える
82

「使用されている」メモリの量が増え続けない限り、メモリリークとは見なしません。解放されていないメモリがあることは理想的ではありませんが、必要なメモリの量が増え続けない限り、大きな問題にはなりません。

于 2008-11-07T19:06:51.423 に答える
79

まず、定義を正しくしましょう。メモリリークとは、メモリが動的に割り当てられた場合(たとえば、を使用したmalloc()場合)であり、対応する空きがないと、メモリへのすべての参照が失われます。簡単な作成方法は次のとおりです。

#define BLK ((size_t)1024)
while(1){
    void * vp = malloc(BLK);
}

while(1)ループの前後で、1024(+オーバーヘッド)バイトが割り当てられ、新しいアドレスがvpに割り当てられることに注意してください。以前のmallocされたブロックへのポインタは残っていません。このプログラムは、ヒープがなくなるまで実行されることが保証されており、mallocされたメモリを回復する方法はありません。記憶はヒープから「漏れ」ており、二度と見られることはありません。

あなたが説明していることは、しかし、次のように聞こえます

int main(){
    void * vp = malloc(LOTS);
    // Go do something useful
    return 0;
}

メモリを割り当て、プログラムが終了するまでそれを操作します。これはメモリリークではありません。プログラムを損なうことはなく、プログラムが終了すると、すべてのメモリが自動的に消去されます。

通常、メモリリークは回避する必要があります。第一に、あなたの上の高度やハンガーでの燃料補給のように、漏れて回復できない記憶は役に立たない。第2に、後でメモリリークを見つけるよりも、最初にメモリリークを行わずに、正しくコーディングする方がはるかに簡単です。

于 2008-11-08T06:02:47.120 に答える
41

理論的にはありませんが、実際には依存します

これは、プログラムが処理しているデータの量、プログラムが実行される頻度、およびプログラムが常に実行されているかどうかによって異なります。

少量のデータを読み取って計算を行い、終了するクイックプログラムがある場合、小さなメモリリークに気付くことはありません。プログラムはあまり長く実行されておらず、少量のメモリしか使用しないため、プログラムが存在する場合、リークは小さく、解放されます。

一方、数百万のレコードを処理して長時間実行するプログラムがある場合、わずかなメモリリークにより、十分な時間が与えられたマシンがダウンする可能性があります。

リークのあるサードパーティのライブラリについては、問題が発生した場合は、ライブラリを修正するか、より適切な代替ライブラリを見つけてください。それが問題を引き起こさないのであれば、それは本当に重要ですか?

于 2008-11-07T19:05:12.267 に答える
37

多くの人は、メモリを解放するとすぐにオペレーティング システムに返され、他のプログラムで使用できるという印象を受けているようです。

これは正しくありません。オペレーティング システムは通常、メモリを 4KiB ページで管理します。mallocおよびその他の種類のメモリ管理は、OS からページを取得し、必要に応じてサブ管理します。プログラムが後でより多くのメモリを malloc すると仮定すると、オペレーティング システムにページが返されない可能性が非常に高くなりfree()ます。

free()決してメモリをオペレーティング システムに返さないと言っているわけではありません。これは、特に大量のメモリを解放している場合に発生する可能性があります。しかし、保証はありません。

重要な事実:不要になったメモリを解放しないと、さらに malloc を実行すると、さらに多くのメモリが消費されることが保証されます。ただし、最初に解放すると、代わりに解放されたメモリが malloc によって再利用される可能性があります。

これは実際にはどういう意味ですか?これは、プログラムが今後これ以上メモリを必要としないことがわかっている場合 (たとえば、クリーンアップ フェーズにある場合)、メモリを解放することはそれほど重要ではないことを意味します。ただし、後でプログラムがより多くのメモリを割り当てる可能性がある場合は、メモリ リーク (特に繰り返し発生する可能性があるもの) を回避する必要があります。

また、終了直前にメモリを解放することが悪い理由の詳細については、このコメントを参照してください。

コメント投稿者は、呼び出しfree()によって解放されたメモリを他のプログラムが自動的に使用できるようにしないことを理解していないようでした。しかし、それがこの答えの要点です!

そこで、人々を納得させるために、free() がほとんど役に立たない例を示します。計算を簡単にするために、OS が 4000 バイトのページでメモリを管理していると仮定します。

100 バイトのブロックを 1 万個割り当てるとします (簡単にするために、これらの割り当てを管理するために必要な余分なメモリは無視します)。これは 1MB または 250 ページを消費します。次に、これらのブロックをランダムに 9000 個解放すると、残りは 1000 個のブロックになりますが、ブロックはあちこちに散らばっています。統計的には、約 5 ページが空白になります。他の 245 には、それぞれ少なくとも 1 つの割り当てられたブロックがあります。これは 980KB のメモリに相当し、100KB しか割り当てられていなくても、オペレーティング システムによって再利用される可能性はありません。

一方、プログラムが占有するメモリの量を増やすことなく、さらに 9000 個のブロックを malloc() できるようになりました。

技術的free()にメモリを OS に戻すことができる場合でも、そうしない場合があります。迅速な操作とメモリの節約のバランスを取る必要があります。さらに、すでに大量のメモリを割り当ててから解放したプログラムは、再びそうする可能性があります。Web サーバーは、要求ごとに要求を処理する必要があります。OS に常にメモリを要求する必要がないように、「スラック」メモリを利用できるようにしておくことは理にかなっています。free()

于 2008-11-10T01:05:26.207 に答える
27

アプリケーションの実行後に OS をクリーンアップすることには、概念的に問題はありません。

アプリケーションとその実行方法に大きく依存します。数週間実行する必要があるアプリケーションで継続的に発生するリークには対処する必要がありますが、メモリをあまり必要とせずに結果を計算する小さなツールは問題になりません。

多くのスクリプト言語が循環参照をガベージ コレクションしないのには理由があります。その使用パターンでは、実際の問題ではなく、メモリの浪費と同じくらいリソースの浪費になります。

于 2008-11-07T19:08:27.877 に答える
19

答えはノーだと思います。メモリリークを許してはいけません。明確に述べられていない理由がいくつかあります。ここには素晴らしい技術的な答えがありますが、本当の答えは、より社会的/人間的な理由にかかっていると思います.

(最初に、他の人が述べたように、真のリークは、プログラムが任意の時点で、割り当てたメモリ リソースを追跡できなくなった場合に発生することに注意してください。C では、これはmalloc()、ポインターに移動し、そのポインターがスコープを離れたときに発生します。free()最初。)

ここでの決定の重要なポイントは習慣です。ポインターを使用する言語でコーディングすると、ポインターを大量に使用することになります。そしてポインターは危険です。あらゆる種類の深刻な問題をコードに追加する最も簡単な方法です。

コーディングしているときは、調子に乗ることもあれば、疲れたり、怒ったり、心配になったりすることもあります。やや気が散っている時間に、自動操縦でより多くのコーディングを行っています。自動操縦効果は、1 回限りのコードと大規模なプロジェクトのモジュールを区別しません。そのときに確立した習慣が、最終的にコード ベースに反映されます。

いいえ、メモリ リークを許してはいけません。同じ理由で、車線を変更するときに死角を確認する必要があるのと同じです。アクティブな脳が気が散っている間は、良い習慣だけが悲惨な失敗からあなたを救うことができます.

「習慣」の問題を超えて、ポインターは複雑であり、精神的に追跡するために多くの脳力を必要とすることがよくあります. ポインターの使用に関しては、特にプログラミングに慣れていない場合は、「水を濁す」ことはお勧めしません。

より社会的な側面もあります。malloc()とを適切に使用するfree()ことで、コードを見る人は誰でも安心できます。リソースを管理しています。ただし、そうしないと、すぐに問題が疑われます。

このコンテキストでは、メモリ リークが問題にならないことはわかっているかもしれませんが、コードのメンテナーは全員、そのコードを読むときに頭の中でそれを解決する必要があります。使用free()することで、問題を考慮する必要さえなくなります。

最後に、プログラミングとはプロセスのメンタル モデルを明確な言語で記述して、人間とコンピューターがそのプロセスを完全に理解できるようにすることです。優れたプログラミング手法の重要な部分は、不必要なあいまいさを決して導入しないことです。

スマート プログラミングは柔軟で汎用的です。悪いプログラミングはあいまいです。

于 2008-11-08T18:55:16.733 に答える
18

プログラムのメモリ使用量を減らさない限り、メモリを解放するのは常に間違っているという、一般的ではないが実用的な答えを出します。たとえば、単一の割り当てまたは一連の割り当てを行ってデータセットをロードし、その生涯にわたって使用するプログラムは、何も解放する必要はありません。非常に動的なメモリ要件を持つ大規模なプログラムのより一般的なケース (Web ブラウザを考えてください) では、使用していないメモリをできるだけ早く解放する必要があります (たとえば、タブ/ドキュメント/などを閉じるなど)。 、しかし、ユーザーがクリックして「終了」を選択したときに何かを解放する理由はなく、そうすることは実際にはユーザーエクスペリエンスに有害です。

なんで?メモリを解放するには、メモリに触れる必要があります。システムの malloc 実装がたまたま割り当てられたメモリ ブロックに隣接するメタデータを格納していない場合でも、解放する必要があるすべてのポインターを見つけるためだけに、再帰構造をたどる可能性があります。

ここで、あなたのプログラムが大量のデータを扱ってきたものの、そのほとんどにしばらく触れていなかったとします (繰り返しますが、Web ブラウザーが良い例です)。ユーザーが多くのアプリを実行している場合、そのデータのかなりの部分がディスクにスワップされている可能性があります。exit(0) するか main から戻ると、すぐに終了します。優れたユーザー エクスペリエンス。わざわざすべてを解放しようとすると、すべてのデータを元に戻すのに 5 秒以上かかり、その後すぐに破棄することになります。ユーザーの時間の無駄。ラップトップのバッテリー寿命の無駄。ハードディスクの摩耗の無駄。

これは単なる理論上の話ではありません。あまりにも多くのアプリをロードしてディスクがスラッシングし始めていることに気付いたときはいつでも、「終了」をクリックすることさえ考えません。できるだけ早く端末に到達し、killall -9 と入力します...「終了」するとさらに悪化することがわかっているためです。

于 2010-06-28T06:11:39.970 に答える
15

あなたの状況では、答えは大丈夫だと思います。ただし、メモリ リークが意識的な決定であることを文書化する必要があります。メンテナンス プログラマーがやって来て、コードを関数内に平手打ちし、それを何百万回も呼び出すことは望ましくありません。したがって、リークが問題ないと判断した場合は、将来プログラムに取り組む必要がある人のために、それを (大きな文字で) 文書化する必要があります。

これがサードパーティのライブラリである場合は、トラップされる可能性があります。ただし、このリークが発生したことを確実に文書化してください。

ただし、基本的に、メモリ リークが 512 KB のバッファなどの既知の量である場合、それは問題ではありません。ライブラリ コールを呼び出すたびにメモリ リークが増加し続け、メモリが 512KB 増加し、解放されない場合は、問題が発生している可能性があります。それを文書化し、呼び出しが実行される回数を制御すると、管理しやすい場合があります。しかし、512 は大したことではありませんが、100 万回を超える 512 コールは非常に多いため、本当にドキュメントが必要です。

また、オペレーティング システムのドキュメントを確認する必要があります。これが組み込みデバイスの場合、終了するプログラムからすべてのメモリを解放しないオペレーティング システムが存在する可能性があります。よくわかりませんが、これは正しくないかもしれません。しかし、調べる価値はあります。

于 2008-11-07T19:15:27.740 に答える
11

誰かが「はい」と言う理由を思い付くことができると確信していますが、それは私ではありません。いいえと言う代わりに、これはイエス/ノーの質問であってはならないと言うつもりです。メモリリークを管理または封じ込める方法はいくつかあり、多くのシステムにそれらがあります。

これを計画している地球を離れるデバイス上のNASAシステムがあります。システムは頻繁に自動的に再起動するため、メモリリークが操作全体に致命的な影響を与えることはありません。封じ込めの一例です。

于 2008-11-07T19:07:13.823 に答える
8

メモリを割り当てて、プログラムの最後の行まで使用する場合、それはリークではありません。メモリの量が増えていなくても、メモリを割り当てて忘れてしまうと、それは問題になります。割り当てられたが未使用のメモリが原因で、他のプログラムの実行が遅くなったり、まったく実行されなかったりする可能性があります。

于 2008-11-07T19:13:32.937 に答える
8

これまでに見た「無害な」リークの数は、片手で数えることができます。

したがって、答えは非常に適格な「はい」です。

例。循環キューまたはデキューを格納するためのバッファーが必要であるが、必要なバッファーの大きさがわからず、ロックまたはすべてのリーダーのオーバーヘッドを許容できないシングルトン リソースがある場合は、指数関数的に倍増するバッファーを割り当てますが、古いものを解放しないと、キュー/キューごとに限られた量のメモリがリークします。これらの利点は、すべてのアクセスを劇的に高速化し、ロックの競合の危険を冒さないことでマルチプロセッサ ソリューションの漸近線を変更できることです。

このアプローチは、CPU ごとのワークスティーリング deques など、非常に明確に固定されたカウントを持つものに大きな利益をもたらし、/proc/self/mapsHans Boehm の保守的な C のガベージ コレクターでシングルトン状態を保持するために使用されるバッファーでは、はるかに少ない程度で使用されるのを見てきました。ルート セットなどの検出に使用される /C++。

技術的にはリークですが、これらのケースはどちらもサイズに制限があり、拡張可能な循環ワーク スティーリング デキュー ケースでは、キューのメモリ使用量が制限付きで 2 倍に増加する代わりに、パフォーマンスが大幅に向上します

于 2008-11-07T20:41:16.457 に答える
8

プログラムの開始時に大量のヒープを割り当て、終了時にそれを解放しない場合、それ自体はメモリ リークではありません。メモリ リークとは、プログラムがコードのセクションをループし、そのコードがヒープを割り当てた後、ヒープを解放せずに「追跡を失う」ことです。

実際、終了する直前に free() または delete を呼び出す必要はありません。プロセスが終了すると、そのメモリはすべて OS によって再利用されます (これは確かに POSIX の場合です。他の OS、特に組み込み OS では YMMV)。

終了時にメモリを解放しないことに関して私が持っている唯一の注意は、たとえば、プログラムをリファクタリングして、入力を待機するサービスになり、プログラムが行うことを何でも実行し、ループして待機することです。別のサービス呼び出しを行うと、コーディングした内容がメモリ リークに変わる可能性があります。

于 2008-11-07T20:44:41.350 に答える
6

この種の質問では、コンテキストがすべてです。個人的にはリークに耐えられず、私のコードでは、リークが発生した場合は修正するために多大な努力を払っていますが、リークを修正する価値があるとは限りません。彼らのコードのリークを修正するために私が支払う価値はないと彼らに言いました。例を挙げましょう:

私はプロジェクトのトリアージを行い、いくつかのパフォーマンス作業を行い、多くのバグを修正していました。アプリケーションの初期化中にリークがあり、それを追跡して完全に理解しました。それを適切に修正するには、それ以外の場合は機能するコードの一部をリファクタリングするのに 1 日ほどかかるでしょう。ハックなことをすることもできましたが (値をグローバルに詰め込んで、もう使用されていないことがわかっているポイントを取得して解放するなど)、コードに触れなければならない次の人にさらに混乱を招くだけでした。

個人的には、そもそもそのようにコードを書くことはなかったでしょうが、私たちのほとんどは、常に手付かずの適切に設計されたコードベースで作業できるわけではありません。150 バイトのリークを修正するのにかかったであろう時間は、代わりに数メガバイトの RAM を削減するアルゴリズムの改善に費やされる可能性があります。

最終的に、約 1 ギガの RAM を使用し、専用のマシンで実行されるアプリで 150 バイトのリークが発生することは、修正する価値がないと判断したため、リークされた、修正するには何を変更する必要があるかというコメントを書きました。それ、そしてなぜ当時それが価値がなかったのか。

于 2008-11-07T19:33:04.257 に答える
5

これは非常にドメイン固有であるため、答える価値はほとんどありません。おかしな頭を使ってください。

  • スペース シャトル オペレーティング システム: いいえ、メモリ リークは許可されません
  • 迅速な開発の概念実証コード: これらすべてのメモリ リークを修正するのは時間の無駄です。

そして、さまざまな中間状況があります。

製品のリリースを遅らせて最悪のメモリ リーク以外をすべて修正することの機会費用 ($$$) は、通常、「ずさんでプロフェッショナルではない」という感情を小さくします。あなたの上司はあなたにお金を稼ぐためにお金を払っています。

于 2008-11-07T19:13:31.237 に答える
5

ほとんどの回答は実際のメモリリークに集中していますが (これはずさんなコーディングの兆候であるため、これまで問題ありませんでした)、質問のこの部分は私にとってより興味深いようです:

メモリを割り当てて、アプリケーションのコードの最後の行 (たとえば、グローバル オブジェクトのデコンストラクタ) まで使用するとどうなるでしょうか。メモリ消費量が時間の経過とともに増加しない限り、(Windows、Mac、および Linux で) アプリケーションが終了したときに OS がメモリを解放することを信頼しても問題ありませんか? OSによって解放されるまでメモリが継続的に使用されていた場合、これを実際のメモリリークと見なすことさえできますか.

関連するメモリが使用されている場合、プログラムが終了する前に解放することはできません。解放がプログラムの終了によって行われるか、OS によって行われるかは問題ではありません。これが文書化されている限り、変更によって実際のメモリ リークが発生することはなく、画像に C++ デストラクタまたは C クリーンアップ関数が含まれていない限り。閉じられていないファイルは、リークされたFILEオブジェクトによって明らかになる可能性がありますが、fclose() が欠落しているためにバッファーがフラッシュされない可能性もあります。

したがって、元のケースに戻ると、それ自体は完全に問題ないので、最も強力なリーク検出器の 1 つである Valgrind は、要求された場合にのみそのようなリークを処理します。Valgrind では、ポインタを事前に解放せずに上書きすると、メモリ リークと見なされます。これは、メモリ リークが再発する可能性が高く、ヒープが無限に大きくなる可能性が高いためです。

次に、まだ到達可能な nfreed メモリ ブロックはありません。出口でそれらすべてを確実に解放することもできますが、それ自体が時間の無駄です。ポイントは、前に解放できるかどうかです。いずれにせよ、メモリ消費量を減らすことは役に立ちます。

于 2009-01-12T03:23:01.987 に答える
5

まず、認識されているメモリ リークと実際のメモリ リークには大きな違いがあることを認識する必要があります。非常に頻繁に、分析ツールは多くのレッドニシンを報告し、実際にはリークしていない場所 (メモリまたはハンドルなどのリソース) にリークがあったとラベル付けします。多くの場合、これは分析ツールのアーキテクチャが原因です。たとえば、特定の分析ツールは、実行時オブジェクトが解放されたことを認識しないため、これらのオブジェクトをメモリ リークとして報告します。ただし、割り当て解除はランタイムのシャットダウン コードで発生するため、分析ツールでは確認できない可能性があります。

そうは言っても、見つけるのが非常に難しい、または修正するのが非常に難しい実際のメモリリークが発生する場合があります。では、コードにそれらを残しても問題ないのでしょうか?

理想的な答えは、「いいえ、決してありません」です。より現実的な答えは、「いいえ、ほとんどありません」かもしれません。実生活では、リソースの数と解決する時間が限られており、タスクのリストが無限にあることがよくあります。タスクの 1 つがメモリ リークを排除する場合、収穫逓減の法則が頻繁に作用します。アプリケーションのすべてのメモリ リークの 98% を 1 週間で解消できますが、残りの 2% には数か月かかる場合があります。場合によっては、アプリケーションのアーキテクチャが原因で、コードを大幅にリファクタリングしなければ、特定のリークを排除することが不可能になることさえあります。残りの 2% を排除することのコストと利点を比較検討する必要があります。

于 2008-11-07T19:15:09.190 に答える
4

「既知の」メモリリークが大混乱を引き起こさないと確信している場合でも、そうしないでください。せいぜい、別の時間と場所で、同様の、おそらくより重大な間違いを犯す道を開くでしょう.

私にとって、これを尋ねることは、「誰もいない朝の午前 3 時に赤信号を消してもいいですか?」と質問するようなものです。確かに、その時は問題にならないかもしれませんが、ラッシュアワーに同じことをするためのレバーを提供します!

于 2008-11-07T20:32:54.620 に答える
4

メモリ リークが実際に何であるかについて、非常に多くの間違った定義があることに驚いています。具体的な定義がないと、悪いことか悪いことかの議論は進まない。

一部のコメンターが正しく指摘しているように、メモリリークは、プロセスによって割り当てられたメモリが範囲外になり、プロセスが参照または削除できなくなった場合にのみ発生します。

ますます多くのメモリを取得しているプロセスが、必ずしもリークしているとは限りません。そのメモリを参照して割り当てを解除できる限り、メモリはプロセスの明示的な制御下にあり、リークしていません。特にメモリが限られているシステムのコンテキストでは、プロセスの設計が不適切である可能性がありますが、これはリークと同じではありません。逆に、たとえば 32 バイトのバッファのスコープを失うことは、リークされるメモリの量が小さい場合でも、依然としてリークです。これが重要ではないと思われる場合は、誰かがアルゴリズムをライブラリ呼び出しにラップして 10,000 回呼び出すまで待ち​​ます。

自分のコードのリークを許可する理由はまったくありませんが、どんなに小さくても. C や C++ などの最新のプログラミング言語は、プログラマーがこのようなリークを防ぐために多大な努力を払っており、特に特定の言語機能と組み合わせた場合に、リークを防ぐために優れたプログラミング手法を採用しないという正当な議論はめったにありません。

既存またはサードパーティのコードに関しては、品質または変更を行う能力に対する制御が非常に制限されている可能性があるため、リークの重大度に応じて、プロセスを定期的に再起動して削減するなどの緩和措置を受け入れるか、実行することを余儀なくされる場合があります。漏れの影響。

既存の (漏洩している) コードを変更または置換することはできない可能性があるため、それを受け入れざるを得ない場合があります。ただし、これは大丈夫だと宣言することと同じではありません。

于 2016-04-11T09:55:26.940 に答える
4

私は vfilby に同意します – それは場合によります。Windows では、メモリ リークを比較的重大なバグとして扱います。しかし、それはコンポーネントに大きく依存します。

たとえば、メモリ リークは、めったに実行されず、限られた期間しか実行されないコンポーネントの場合、それほど深刻ではありません。これらのコンポーネントは実行され、作業を行ってから終了します。それらが終了すると、すべてのメモリが暗黙的に解放されます。

ただし、サービスやその他の長期実行コンポーネント (シェルなど) でのメモリ リークは非常に深刻です。その理由は、これらのバグが時間の経過とともにメモリを「盗む」ためです。これを回復する唯一の方法は、コンポーネントを再起動することです。ほとんどの人は、サービスやシェルを再起動する方法を知りません。そのため、システムのパフォーマンスが低下した場合、再起動するだけです。

したがって、リークがある場合は、その影響を 2 つの方法で評価します

  1. あなたのソフトウェアとあなたのユーザーの経験に。
  2. システムリソースを節約するという点で、システム(およびユーザー)にとって。
  3. メンテナンスと信頼性に対する修正の影響。
  4. 他の場所で回帰を引き起こす可能性。

フォアデッカー

于 2008-11-07T19:15:33.387 に答える
4

いいえ、OS がクリーンアップするようなリークがあってはなりません。その理由(私が確認できる限り、上記の回答には記載されていません)は、 main() がいつ別のプログラムで関数/モジュールとして再利用されるかわからないためです。あなたの main() が他の人のソフトウェアで頻繁に呼び出される関数になった場合、このソフトウェアには時間の経過とともにメモリを消費するメモリ リークが発生します。

KIV

于 2008-11-16T07:36:03.757 に答える
3

メモリ リークを意図したプログラムを作成している場合 (つまり、メモリ リークがシステム パフォーマンスに与える影響をテストする場合) は問題ないと思います。

于 2010-09-18T20:04:21.487 に答える
2

意図的である場合は実際にはリークではなく、大量のメモリがない限り問題はありません。または、大量のメモリに成長する可能性があります。プログラムの存続期間中にグローバル割り当てをクリーンアップしないことはかなり一般的です。リークがサーバーまたは長時間実行されているアプリにある場合は、時間の経過とともに大きくなり、問題が発生します。

于 2008-11-07T19:07:00.783 に答える
2

あなたはあなた自身の質問に答えたと思います。最大の欠点は、メモリリーク検出ツールとの干渉ですが、特定の種類のアプリケーションにとっては大きな欠点だと思います。

私は堅実であると思われるレガシーサーバーアプリケーションを使用していますが、リークがあり、グローバルがメモリ検出ツールの邪魔になります。それは大したことです。

ジャレド・ダイアモンドの「崩壊」という本の中で、著者は、イースター島の最後の木、島を降りるためのカヌーを作るために必要だった木を切り倒した男が何を考えていたのか疑問に思います。その最初のグローバルがコードベースに追加されたのは、何年も前のことだと思います。それはそれが捕らえられるべきだった日でした。

于 2008-11-07T19:07:51.530 に答える
2

原則として、回避できないと感じるメモリリークがある場合は、オブジェクトの所有権についてより深く考える必要があります。

しかし、あなたの質問に対する私の答えは、一言で言えば、本番コードではそうです。開発中はありません。これは逆に思えるかもしれませんが、私の理由は次のとおりです。

あなたが説明する状況では、メモリはプログラムの最後まで保持されますが、それを解放しなくてもまったく問題ありません。プロセスが終了すると、OSはとにかくクリーンアップします。実際、ユーザーエクスペリエンスが向上する可能性があります。私が取り組んだゲームでは、プログラマーは、終了する前にすべてのメモリを解放する方がクリーンであり、プログラムのシャットダウンに最大30分かかると考えていました。代わりに、exit()を呼び出すだけの簡単な変更により、プロセスがすぐに消え、ユーザーは目的のデスクトップに戻りました。

しかし、あなたはデバッグツールについて正しいです:それらは適合を投げます、そしてすべての誤検知はあなたの本当のメモリリークを見つけるのを苦痛にするかもしれません。そのため、常にメモリを解放するデバッグコードを記述し、出荷時に無効にします。

于 2008-11-11T19:27:17.027 に答える
2

次のようなすべてのシナリオの質問と同じ問題が見られます。プログラムが変更され、突然、その小さなメモリ リークが 1,000 万回呼び出され、プログラムの最後が別の場所にあるため、問題になるとどうなりますか? ライブラリにある場合は、ライブラリのメンテナーにバグを記録してください。自分のコードにリークを入れないでください。

于 2008-11-07T19:08:55.070 に答える
2

いいえと答えます。

理論的には、混乱したままにしておくと、オペレーティング システムがクリーンアップします (これは失礼ですが、コンピューターには感情がないため、許容される場合があります)。ただし、プログラムの実行時に発生する可能性のあるすべての状況を予測することはできません。したがって (何らかの動作の正式な証明を行うことができない限り)、メモリ リークを作成することは、プロの観点からは無責任でずさんなものです。

サードパーティのコンポーネントがメモリ リークを起こした場合、これはその影響が差し迫っているという理由だけでなく、プログラマーの作業がずさんであり、これが他のメトリックにも影響を与える可能性があることを示しているため、それを使用することに対する非常に強力な議論となります。さて、レガシー システムを考えると、これは難しいことですが (ウェブ ブラウジング コンポーネントを考えてみてください。私の知る限り、それらはすべてメモリ リークします)、それは標準のはずです。

于 2008-11-07T19:12:19.070 に答える
2

これはすでにうんざりして議論されました。肝心なのは、メモリ リークはバグであり、修正する必要があるということです。サード パーティのライブラリがメモリ リークを起こした場合、他に何が問題なのか疑問に思うことはありませんか? あなたが車を作っているとしたら、時々オイルが漏れるエンジンを使いますか? 結局のところ、エンジンを作ったのは他の誰かなので、それはあなたのせいではなく、あなたが修理することはできませんよね?

于 2008-11-07T22:22:18.407 に答える
2

通常、スタンドアロン アプリケーションでのメモリ リークは、プログラムの終了時にクリーンアップされるため、致命的ではありません。

終了しないように設計されたサーバー プログラムに対して何をしますか?

あなたが、リソースが正しく割り当てられて解放されるコードを設計および実装しないようなプログラマーである場合、私はあなたやあなたのコードとは何の関係も持ちたくありません。リークしたメモリをクリーンアップしたくない場合は、ロックはどうしますか? あなたも彼らをそこにぶら下げたままにしますか?さまざまなディレクトリに一時ファイルの糞を少し残していますか?

そのメモリをリークして、プログラムにクリーンアップさせますか? いいえ、絶対に違います。それは、バグ、バグ、さらに多くのバグにつながる悪い習慣です。

自分で片付けてください。Yo momma もうここで働かないで。

于 2008-11-07T22:24:15.207 に答える
2

はい、メモリ リークは 2 つの悪のいずれかである可能性があります。正確性は重要ですが、メモリを完全に解放すると、システムのパフォーマンスや安定性が影響を受ける可能性があります。メモリを解放してオブジェクトを破棄するのにかかるリスクと時間は、プロセスを終了するよりも望ましくない場合があります。

一般に、メモリを残しておくことは通常は受け入れられません。コードが実行されるすべてのスコープを理解することは困難であり、場合によっては、リークが壊滅的なものになる可能性があります。

メモリを割り当てて、アプリケーションのコードの最後の行 (グローバル オブジェクトのデストラクタなど) まで使用するとどうなるでしょうか。

この場合、コードはより大きなプロジェクト内に移植される可能性があります。これは、オブジェクトの有効期間が長すぎる (必要なインスタンスだけでなく、プログラム全体で持続する) か、グローバルが作成および破棄された場合にリークすることを意味する場合があります。

アプリケーションが終了したときに、OS がメモリを解放してくれることを信頼しても問題ありませんか?

短期間のプログラムが大きなC++コレクション (例: std::map) を作成する場合、オブジェクトごとに少なくとも 2 つの割り当てがあります。オブジェクトを破棄するためにこのコレクションを反復処理すると、CPU にリアルタイムで時間がかかり、オブジェクトがリークして OS によって片付けられるままになると、パフォーマンス上の利点があります。カウンターは、OS によって整頓されていないリソース (共有メモリなど) があり、コード内のすべてのオブジェクトを破棄しないと、これらの解放されていないリソースにいくつかのリソースが保持されているというリスクが生じます。

サードパーティの図書館があなたにこの状況を強制した場合はどうなりますか?

closeまず、リソースを解放する関数のバグを発生させます。それが受け入れられるかどうかの問題は、ライブラリが提供する利点 (コスト、パフォーマンス、信頼性) が、他のライブラリで実行したり、自分で作成したりするよりも優れているかどうかに基づいています。

一般に、ライブラリが再初期化されない限り、私はおそらく気にしません。

メモリリークが報告されるまでの許容時間。

  1. シャットダウン中のサービス。ここでは、時間のパフォーマンスと正確さの間にトレードオフがあります。
  2. 破壊できない壊れた物体。失敗したオブジェクトを検出することができました (例: 例外がキャッチされたため)。オブジェクトを破棄しようとすると、結果はハング (保持されたロック) になります。
  3. メモリ チェッカーの誤報告。

シャットダウン中のサービス

オペレーティング システムをオフにしようとしている場合は、すべてのリソースが整頓されます。通常のプロセスのシャットダウンを実行しないことの利点は、オフにしたときにユーザーがより迅速なパフォーマンスを得られることです。

壊れたオブジェクト

私の過去の中で、オブジェクトが特定のポイントでクラッシュすると壊れてしまい、そのオブジェクトの後続のすべての機能がハングするというオブジェクトを見つけました (そしてそのチームに欠陥を提起しました)。

メモリ リークを無視するのは適切ではありませんが、ハングするよりも、プロセスをシャットダウンしてオブジェクトとそのメモリをリークする方が生産的でした。

リークチェッカーの誤報告

一部のリーク チェッカーは、オブジェクトをインストルメント化し、グローバルと同じように動作します。別のグローバル オブジェクトに有効なデストラクタがあり、終了後に呼び出されてメモリが解放されることを見逃してしまうことがあります。

于 2017-08-05T10:53:21.483 に答える
2

歴史的に、一部のオペレーティング システムでは、一部のエッジ ケースで問題がありました。これらのエッジ ケースは、将来存在する可能性があります。

以下に例を示します。Sun 3 時代の SunOS では、プロセスが exec (またはより伝統的に fork してから exec) を使用した場合、後続の新しいプロセスが親プロセスと同じメモリ フットプリントを継承し、縮小できないという問題がありました。 . 親プロセスが 1/2 ギガのメモリを割り当て、exec を呼び出す前にそれを解放しなかった場合、子プロセスは同じ 1/2 ギガを (割り当てられていなくても) 使用し始めます。この動作は、メモリを大量に消費する SunTools (デフォルトのウィンドウ システム) で最もよく見られました。生成されたすべてのアプリは、fork/exec と継承された SunTools フットプリントを介して作成され、スワップ スペースがすぐにいっぱいになりました。

于 2008-11-07T19:20:07.137 に答える
2

実際の欠点は 1 つしかないと思います。それは、これらの無害なリークがメモリ リーク検出ツールで誤検知として表示されることです。

私が正しく理解していれば、メモリを明示的に解放せず(ポインタがまだあるため解放できます)、プロセスの終了時にOSに依存してメモリを解放します。これは単純なプログラムでは問題ないように思えるかもしれませんが、コードがライブラリに移動され、24 時間年中無休で実行されている常駐デーモン プロセスの一部になる状況を考えてみてください。このデーモンは、コードを使用して何か有用なことを行う必要があるたびにスレッドを生成し、1 時間ごとに数千のスレッドを生成するとします。この場合、実際のメモリ リークが発生します。

残念ながら、このような状況は実際には起こりそうになく、一貫したメモリ管理手法によって作業が楽になる場合があります。

于 2013-08-07T13:38:51.197 に答える
1

アプリケーションがシャットダウンするときは、メモリを解放しないのが最善であると主張できます。

理論的には、OS はアプリケーションが使用するリソースを解放する必要がありますが、この規則の例外となるリソースが常に存在します。だから用心してください。

アプリケーションを終了するだけの利点:

  1. OS は、多くの小さなチャンクではなく、1 つのチャンクを解放します。これは、シャットダウンがはるかに高速であることを意味します。特にWindowsではメモリ管理が遅いです。

終了するだけの悪い点は、実際には次の 2 つの点です。

  1. OS が追跡しないリソースを解放することを忘れたり、OS が解放時に少し待機する可能性があることを忘れがちです。一例は TCP ソケットです。
  2. メモリ追跡ソフトウェアは、終了時に解放されていないものをすべてリークとして報告します。

このため、2 つのシャットダウン モードが必要になる場合があります。1 つはエンド ユーザー向けの迅速でダーティなモードで、もう 1 つは開発者向けの低速で完全なシャットダウン モードです。必ず両方をテストしてください:)

于 2008-11-19T12:22:53.363 に答える
1

私は高校で C のクラスを 1 つ取りましたが、先生は malloc するときは必ず解放するように言いました。

しかし、私が別のコースの大学を受講したとき、教授は、1 秒しか実行されない小さなプログラムを解放しなくても大丈夫だと言いました。したがって、プログラムに害はないと思いますが、強力で健全なコードを解放することをお勧めします。

于 2010-05-01T19:28:35.177 に答える
1

「メモリリーク」の定義は、「自分でクリーンアップしないメモリ」のようです。最近のすべての OS は、プログラムの終了時にそれを解放します。ただし、これは C++ の質問であるため、問題のメモリを適切な範囲内にラップするだけstd::auto_ptrで、範囲外になると削除が呼び出されます。

于 2008-11-07T23:54:36.753 に答える
1

それは、メモリ リークを作成するオブジェクトの使用法に大きく依存します。オブジェクトを使用しているアプリケーションの存続期間中に何度もオブジェクトを作成している場合、そのように使用するのは良くありません。非常に多くのメモリリークが発生するためです。一方、メモリを消費せず、少量のリークのみのオブジェクトの単一インスタンスがある場合、それは問題ではありません。

アプリケーションの実行中にメモリ リークが増加すると、メモリ リークが問題になります。

于 2008-11-12T15:48:24.143 に答える
1

ここにいくつかの素晴らしい答えがあります。この質問に別の視点を追加するために、メモリ リークが許容されるだけでなく、望ましいケースに対処します。Windows ドライバー環境では、開発者は必要に応じて OS によって実行される一連のコールバックを提供します。コールバックの 1 つは「シャットダウン」コールバックで、システムがシャットダウン/再起動される前に実行されます。標準的な状況とは異なり、メモリの解放が不要なだけでなく (システムはすぐにオフになります)、シャットダウンをできるだけ速くしてメモリ管理のオーバーヘッドを防ぐために、推奨されません。

于 2018-05-24T01:35:56.857 に答える
1

私は JohnMcG に完全に同意します。ただ、良性のメモリ リークがあると認められているという理由だけで、実際の潜在的に重大なメモリ リークを発見するのに問題があったことを付け加えたいと思います。これらが時間の経過とともに非常に多くなると、無害なものの洪水の中で深刻なものを検出することがますます難しくなります.

したがって、少なくとも仲間のプログラマーのために (そして将来のあなた自身のためにも)、できるだけ早くそれらを排除するようにしてください。

于 2008-11-07T19:29:46.617 に答える
0

いいえ、問題ありませんが、アロケータ、メモリダンパー、リークディテクタをいくつか実装しましたが、実用的な問題として、このような割り当てに「リークではない」とマークを付けると便利であることがわかりました。リークレポートが懸念されます」 ..。

これは、リークレポートをより便利にするのに役立ちます...そして「プログラムの終了によって解放されない静的スコープでの動的割り当て」で混雑しません

于 2009-03-23T01:48:21.923 に答える
0

ほんの数秒で実行されてから終了するプログラムがあれば大丈夫だと思います。それは個人的な使用のためだけのものです。プログラムが終了するとすぐに、メモリリークはクリーンアップされます。

問題は、長時間実行されるプログラムがあり、ユーザーがそれに依存している場合に発生します。また、いつかそのコードを別のものに変える可能性がある場合は特に、作業のためにプログラムにメモリリークを存在させることは悪いコーディング習慣です。

全体として、メモリリークを取り除く方がよいでしょう。

于 2010-03-07T19:13:34.670 に答える
0

アプリケーションが後で別のアプリケーションから使用される場合を考えてみてください。いくつかのアプリケーションを別々のウィンドウで開いたり、何かを実行するために次々に開いたりする可能性があります。プロセスではなくライブラリとして実行されている場合は、メモリ クリーンアップをコールド スキップしたと思われるため、呼び出し側プログラムでメモリ リークが発生します。

自動的にそれを行うある種のスマート ポインターを使用します (例: Boost ライブラリの scoped_ptr)。

于 2010-07-27T12:07:51.563 に答える
0

ルールは簡単です。メモリを使い終わったら、それを消去します。後でいくつかのインスタンスが必要になる場合でも、メモリを大量に使用するため、ディスクへのスワップが原因でパフォーマンスに影響を与える可能性があることに注意してください。ディスク内のファイルにデータを保存し、それらをリロードした後、この手法によりプログラムが大幅に最適化されることがあります。 .

于 2011-01-26T15:05:23.697 に答える
0

少し前までは、プログラムにいくらかのメモリ リークが発生することは許容される場合がある (まだラピッド プロトタイピング中です) と、はいと言っていました。機能エラー。プログラムのリークは、データ エンティティのライフ サイクルが実際にはわかっていない場合に発生します。これは、分析が大幅に不足していることを示しています。結論として、プログラムで何が起こるかを知ることは常に良い考えです。

于 2010-06-29T20:05:43.970 に答える
0

おそらく、髪を分割します。アプリが UNIX で実行されていて、ゾンビになる可能性がある場合はどうなるでしょうか? この場合、メモリは OS によって再利用されません。したがって、プログラムが終了する前にメモリの割り当てを解除する必要があります。

于 2009-08-14T00:43:30.890 に答える
0

プログラムがメモリを再び必要とすることはないため、メモリを解放しても何の影響もないため、プログラムの最後の行でメモリの解放を省略してもまったく問題ありません。

于 2009-11-01T11:53:53.343 に答える
0

1 つの場合のみ: 回復不能なエラーが原因で、プログラムが自動的に停止します。

于 2009-01-07T06:58:21.220 に答える
0

メモリ使用率が時間の経過とともに増加しない限り、それは依存します。サーバー ソフトウェアで多くの複雑な同期を行っている場合、たとえばシステム コールでブロックするバックグラウンド スレッドを開始している場合、クリーン シャットダウンを行うのは複雑すぎて正当化できない場合があります。この状況では、代替手段は次のとおりです。

  1. プロセスが終了するまでメモリをクリーンアップしないライブラリ。
  2. 余分な 500 行のコードを記述し、別のミューテックスと条件変数をクラスに追加して、テストから完全にシャットダウンできるようにします。ただし、このコードは、サーバーがクラッシュによってのみ終了する本番環境では使用されません。
于 2008-11-16T07:08:03.063 に答える
0

の末尾まで使用している場合main()は、単にリークではありません (もちろん、保護されたメモリ システムを想定しています!)。

実際、プロセスのシャットダウン時にオブジェクトを解放することは、あなたが行うことができる絶対に最悪のことです.OSは、作成したすべてのページに戻る必要があります. ファイル ハンドル、データベース接続、確かに閉じますが、メモリを解放するのはばかげています。

于 2009-02-27T05:43:47.660 に答える