web-dev-qa-db-ja.com

メモリリークは今までに大丈夫ですか?

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

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

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

実際の欠点は1つしかありません。つまり、これらの良性リークは、メモリリーク検出ツールで誤検出として表示されるということです。

225
Imbue

番号。

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

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

それも私の人生をシンプルにします。メモリリークを検出した場合、「許容可能な」メモリリークであるかどうかを判断するために、詳細な決定ツリー構造を実行するのではなく、それを削除します。

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

しかし、最終的には専門家としての規律の問題です。コンパイラの警告を許容し、メモリリークを許容することは悪い習慣であり、最終的には後から噛みつきます。

物事を極端なものにするために、外科医が患者の体内に手術器具を置いておくのは容認できるでしょうか?

SurgeonOverflow.comに投稿されたこの質問を見た場合、その機器を取り外すコスト/リスクがそれを残すコスト/リスクを超える状況が発生する可能性があり、無害である状況が存在する可能性があります「いいえ」以外の答えを見つけた場合、医療専門職に対する自信が著しく損なわれます。

第三者の図書館がこの状況を私に押し付けた場合、問題の図書館の全体的な品質を真剣に疑うことになります。それはまるで車をテストして、カップホルダーの1つに2つのゆるいワッシャーとナットを見つけたかのようになります。

325
JohnMcG

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

80
Jim C

最初に定義を修正しましょう。メモリleakは、たとえば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;
}

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

一般に、メモリリークを回避する必要があります。まず、あなたの上の高度と格納庫で燃料を補給するように、漏れて回復できないメモリは無用です。第二に、後でメモリリークを見つけるよりも、開始時にメモリをリークしないように正しくコーディングする方がはるかに簡単です。

79
Charlie Martin

理論的には、実際には依存するです。

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

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

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

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

39
vfilby

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

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

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

重要な事実:不要になったメモリを解放しないと、さらにmallocが消費することが保証されますメモリ。ただし、最初に解放すると、mallocは解放されたメモリを代わりに再使用する場合があります。

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

終了直前にメモリを解放するのが悪い理由の詳細については、 this comment も参照してください。

コメンターは、free()を呼び出しても、他のプログラムが解放されたメモリを使用することを自動的に許可しないことを理解していないようでした。しかし、それがこの答えのポイントです!

したがって、人々を納得させるために、free()がほとんど役に立たない例を示します。数学をわかりやすくするために、OSがメモリを4000バイトページで管理しているふりをします。

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

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

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

36
Artelius

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

本当にアプリケーションとそれがどのように実行されるかに依存します。数週間実行する必要のあるアプリケーションで継続的に発生するリークは処理する必要がありますが、メモリの必要量が多すぎることなく結果を計算する小さなツールは問題になりません。

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

27
kasperjj

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

(最初に、他の人が述べたように、プログラムが任意の時点で割り当てたメモリリソースのトラックを失うとき、真のリークがあることに注意してください。Cでは、ポインタにmalloc()し、そのポインターは、最初にfree()を実行せずにスコープから出ます。)

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

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

そのため、現在道路上で唯一の車であっても、車線変更時に盲点を確認する必要があるのと同じ理由で、メモリリークを許可しないでください。 活動中の脳が気を散らしている間、悲惨な失敗からあなたを救うことができるのは良い習慣だけです。

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

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

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

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

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

19
Jason L

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

これがサードパーティのライブラリである場合は、閉じ込められる可能性があります。しかし、このリークが発生することを明確に文書化してください。

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

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

15
Cervo

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

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

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

これは単なる理論的なものではありません。あまりにも多くのアプリがロードされており、ディスクがスラッシングを開始していることに気付いたときはいつでも、「終了」をクリックすることも考えていません。私はできるだけ早くターミナルに行き、killall -9と入力します...「出口」はそれを悪化させるだけだからです。

14
R..

誰かが「はい」と言う理由を考え出すことができると確信していますが、それは私ではありません。 「いいえ」と言う代わりに、これは「はい/いいえ」の質問であってはならないと言います。メモリリークを管理または抑制する方法があり、多くのシステムにメモリリークがあります。

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

11
pearcewg

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

8
Bill the Lizard

時間の経過とともに見た「良性」リークの数を数えることができます。

答えはイエスです。

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

このアプローチは、CPUごとのワークスティーリングdequeなどの非常に明確に固定されたカウントを持つものや、シングルトン/proc/self/mapsルートセットの検出などに使用される、C/C++用のHans Boehmの保守的なガベージコレクターの状態.

技術的にはリークではありますが、これらのケースは両方ともサイズに制限があり、拡張可能な円形ワークスティーリングデックケースでは、hugeパフォーマンスが向上します。キュー。

8
Edward KMETT

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

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

終了時にメモリを解放しない場合の唯一の注意点は、たとえば、プログラムをリファクタリングして、入力を待機するサービスになり、プログラムが何をしても、ループして待機することです別のサービスコール、次にコーディングしたものcanはメモリリークになります。

8
nsayer

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

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

また、さまざまな中間的な状況があります。

最悪のメモリリークを除くすべてを修正するために製品のリリースを遅らせる機会費用($$$)は、通常、「ずさんな、または専門家ではない」という感覚を小さくします。あなたの上司は彼にお金を稼ぐためにあなたに支払います。温かく、曖昧な気持ちを得るためではありません。

6
Dustin Getz

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

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

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

5
John Dibling

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

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

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

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

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

5
Blaisorblade

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

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

個人的には、そもそもそのようにコードを書いたことはありませんでしたが、私たちのほとんどは元のきれいに設計されたコードベースに常に取り組むことができず、時にはこれらを実用的に見なければなりません。その代わりに、150バイトのリークを修正するのにかかった時間は、メガバイトのRAMを削ぎ落とすアルゴリズムの改善に費やすことができました。

最終的に、1ギガバイトのRAMの周りで使用し、専用のマシンで実行したアプリで150バイトをリークすることは修正する価値がないと判断したので、リークするというコメントを書きました。それと、なぜそれが価値がなかったのか。

5
Louis Gerbarg

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

3
Beep beep

メモリリークが実際に何であるかについて、非常に多くの誤った定義を見て驚いています。具体的な定義がなければ、それが悪いことであるかどうかについての議論はどこにも行きません。

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

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

あなた自身のコードのリークを許可する理由は、どんなに小さくてもわかりません。 CやC++などの最新のプログラミング言語は、プログラマーがそのようなリークを防ぐのを支援するために非常に長くなり、特に特定の言語機能と組み合わせた場合に、リークを防ぐために適切なプログラミング手法を採用しないという良い議論はほとんどありません。

既存のコードまたはサードパーティのコードについては、リークの重大度に応じて、品質または変更を行う能力の制御が非常に制限される場合があります。漏れの影響。

既存の(漏えいしている)コードを変更または置換することはできないため、受け入れなければならない場合があります。ただし、これは問題ないと宣言することとは異なります。

3
Component 10

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

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

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

リークがある場合は、2つの方法でその影響を評価してください

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

フォデッカー

3
Foredecker

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

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

3
Ather

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

しかし、あなたの質問に対する私の簡単な答えは、製品コードでは、はい。開発中には、いいえです。これは逆に見えるかもしれませんが、ここに私の推論があります:

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

ただし、デバッグツールについてはあなたは正しいです。デバッグツールは適合します。すべての誤検知により、実際のメモリリークを見つけるのが苦痛になる場合があります。そのため、メモリを解放するデバッグコードを常に記述し、出荷時にはメモリを無効にします。

2
Enno

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

2
Sanjaya R

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

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

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

2
Corey Trager

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

2
tloach

いいえと答えます。

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

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

2
Konrad Rudolph

実際の欠点は1つしかありません。つまり、これらの良性リークは、メモリリーク検出ツールで誤検出として表示されるということです。

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

残念ながら、この状況は現実には起こりそうにありませんし、一貫したメモリ管理技術があなたの人生を楽にするかもしれません。

2
Dmitry Krivenok

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

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

2
plinth

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

2
Dima

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

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

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

そのメモリをリークし、プログラムにクリーンアップさせますか?いいえ、まったく違います。それは悪い習慣であり、バグ、バグ、その他のバグにつながります。

自分の後片付けをしてください。Yomommaはここでは動作しません。

2
EvilTeach

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

しかし、私が別の大学を履修したとき、教授は、ほんの一瞬しか実行されない小さなプログラムのために無料ではない、と言った。したがって、プログラムを害することはないと思いますが、強力で健全なコードのために解放することをお勧めします。

1
azn_person

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

1
Max Lybbert

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

理論上、OSはアプリケーションが使用するリソースを解放する必要がありますが、このルールの例外であるリソースが常にいくつかあります。だから注意してください。

アプリケーションを終了するだけで良い:

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

終了するだけで悪いのは、実際には2つのポイントです。

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

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

1
Jørn Jensen

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

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

1

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

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

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

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

アプリケーションが終了したときに、OSを信頼してメモリを解放してもかまいません

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

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

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

一般に、ライブラリが再初期化されない限り、おそらく心配することはないでしょう。

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

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

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

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

壊れたオブジェクト

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

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

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

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

1
mksteve

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

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

1
Vinay

いいえ、それらは大丈夫ではありませんが、いくつかのアロケーター、メモリダンパー、リークディテクターを実装しました。実際的な問題として、そのような割り当てを「リークレポートに関する限り、リークではない」...

これにより、リークレポートがより便利になります。また、「プログラムの終了によって解放されない静的スコープでの動的割り当て」で混雑することはありません。

0
reechard

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

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

0
Marius K

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

0
Eric M

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

0

ほんの数秒実行してから終了するプログラムがあれば大丈夫だと思います。メモリリークは、プログラムが終了するとすぐにクリーンアップされます。

問題は、長期間にわたって実行されるプログラムがあり、ユーザーがそれに依存している場合に発生します。また、プログラムでメモリリークが存在するようにすることは、特にそのコードがいつか他のコードに変わる可能性がある場合に、コーディング習慣としては不適切です。

全体的に、メモリリークを削除する方が優れています。

0
PJT

1つの場合のみ:回復不能なエラーが原因で、プログラムは自身を撃ちます。

0
Steve Lacey

少し前に、私はイエスと言っていたでしょう、あなたのプログラムでメモリリークを許容することはいつか受け入れられます(それはまだラピッドプロトタイピング中です)が、今では5〜6倍の経験をして、最小限のリークを追跡しても本当に深刻なことを明らかにしました機能エラー。データエンティティのライフサイクルが実際にはわからない場合、プログラムでリークが発生し、分析の粗末な欠如が示されます。結論として、プログラムで何が起こるかを知ることは常に良い考えです。

0

ベストプラクティスは、特に、終了前にクリーンアップする場合でも、システムのアップタイム全体で実行するように設計された何かを作成する場合、割り当てたものを常に解放することです。

その非常に単純なルール..リークを持たないことを意図したプログラミングは、新しいリークを見つけやすくします。あなたはそれがオフにされるたびに地面にガスをスパッタしたことを知って作った車を誰かに販売しますか? :)

クリーンアップ関数の()free()呼び出しが安価な場合、それらを使用してみませんか?

0
Tim Post

プログラムが再びメモリを必要とすることはないため、プログラムの最後の行でメモリを解放することは何にも影響しないので、プログラムの最後の行でメモリを解放することを完全に受け入れます。

0
henle

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

0
mike

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

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

0
Simon Buchan

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

  1. プロセスが終了するまでメモリをクリーンアップしないライブラリ。
  2. 追加の500行のコードを記述し、テストから正常にシャットダウンできるように、別のミューテックスと条件変数をクラスに追加します。ただし、このコードは、サーバーがクラッシュするだけで終了する運用環境では使用されません。
0
Jonathan

コードにメモリリークがあり、既知の「許容可能な」リークがある場合でも、メモリリークツールを使用して「実際の」リークを見つけるのは面倒です。 「許容できる」コンパイラ警告を残すのと同じように、新しい「実際の」警告を見つけるのはより困難になります。

0
Chris Peterson