5

Linux用に作成およびコンパイルしたC++アプリケーションのメモリの安定性を検証したいと思います。これは、1秒あたり10〜20接続の速度で接続しているリモートクライアントに応答するネットワークアプリケーションです。長期的には、アプリが削除の呼び出しを行っていたにもかかわらず、メモリは50MBに増加していました...

調査によると、Linuxはすぐにメモリを解放しません。だからここに私の質問があります:

Linuxに実際に解放したメモリを強制的に解放するにはどうすればよいですか?少なくとも、メモリの安定性を確認するために、これを1回実行したいと思います。それ以外の場合、アプリが実際に保持しているメモリを報告できる信頼できるメモリインジケータはありますか?

4

6 に答える 6

5

メモリリークには、memcheckツールまたはその他のプロファイリングツールでvalgrindを使用することをお勧めします

Valgrindのページから:

Memcheck

メモリ管理の問題を検出し、主にCおよびC++プログラムを対象としています。Memcheckの監視下でプログラムが実行されると、メモリのすべての読み取りと書き込みがチェックされ、malloc / new / free/deleteの呼び出しがインターセプトされます。その結果、Memcheckはプログラムが次のことを検出できます。

  • 割り当てるべきではないメモリにアクセスします(まだ割り当てられていない領域、解放された領域、ヒープブロックの終わりを超えた領域、スタックのアクセスできない領域)。
  • 初期化されていない値を危険な方法で使用します。
  • メモリリーク。
  • ヒープブロックの不正な解放を行います(二重解放、不一致の解放)。
  • 重複するソースと宛先のメモリブロックをmemcpy()および関連する関数に渡します。

Memcheckは、これらのエラーが発生するとすぐに報告し、発生したソース行番号と、その行に到達するために呼び出された関数のスタックトレースを示します。Memcheckは、バイトレベルでのアドレス指定可能性、およびビットレベルでの値の初期化を追跡します。その結果、初期化されていない単一のビットの使用を検出でき、ビットフィールド操作での誤ったエラーを報告しません。Memcheckは、通常よりも約10〜30倍遅いプログラムを実行します。Cachegrind

山塊

Massifはヒーププロファイラーです。プログラムのヒープのスナップショットを定期的に取得することにより、詳細なヒーププロファイリングを実行します。プログラムのどの部分が最も多くのメモリ割り当てを担当しているかに関する情報を含む、時間の経過に伴うヒープ使用量を示すグラフを生成します。グラフは、最も多くのメモリが割り当てられている場所を判別するための詳細情報を含むテキストまたはHTMLファイルによって補足されます。Massifは、通常の約20倍の速度でプログラムを実行します。

valgrindの使用は、目的のスイッチを使用してアプリケーションを実行し、valgrindの入力として指定するのと同じくらい簡単です。

valgrind --tool=memcheck ./myapplication -f foo -b bar
于 2012-12-24T16:55:21.500 に答える
5

あなたが見ているのは、おそらくメモリリークではありません。最近のオペレーティングシステムとmalloc/newヒープはどちらも、メモリの非常に複雑なアカウンティングを実行します。これは、一般的に、非常に良いことです。 OSにメモリを解放させようとすると、アプリケーションのパフォーマンスとシステム全体のパフォーマンスの両方が損なわれる可能性があります。

説明する:

  1. ヒープは、使用するために仮想メモリのいくつかの領域を予約します。mallocされるまで、実際にはコミットされません(物理メモリに支えられています)。

  2. メモリを割り当てます。ヒープはそれに応じて大きくなります。これはタスクマネージャーに表示されます。

  3. ヒープにより多くのメモリを割り当てます。それはもっと成長します。

  4. 手順2で割り当てられたメモリを解放します。ただし、#3のメモリはまだ割り当てられており、ヒープはメモリを圧縮できません(ポインタが無効になるため)。

  5. あなたはmalloc/新しいものを追加します。これは、ステップ#3でメモリが割り当てられたに追加される可能性があります。これは、#2を解放して開いたままの領域に収まらないため、またはヒープマネージャが#によって開いたままのブロックのヒープを検索するのが非効率的であるためです。 2.2。(ヒープの実装と、割り当て/解放されるメモリのチャンクサイズによって異なります)

それで、ステップ2のその記憶は今や世界に死んでいるのでしょうか?必ずしも。一つには、それが効率的になれば、おそらく最終的には再利用されるでしょう。再利用されない場合、オペレーティングシステム自体がCPUの仮想メモリ機能(TLB)を使用して、未使用のメモリをアプリケーションの下から直接「再マップ」し、別のアプリケーションに割り当てることができる場合があります。はえ。ヒープはこれを認識しており、通常、OSがページを再マップする機能を改善するのに役立つ方法で物事を管理します。

これらは貴重なメモリ管理手法であり、ProcessExplorerを介したきめ細かいメモリリーク検出をほとんど役に立たないものにするという軽減されない副作用があります。 ヒープ内の小さなメモリリークを検出する場合は、ランタイムヒープリーク検出ツールを使用する必要があります。Windowsでもビルドできるとおっしゃっていたので、MicrosoftのCRTには適切なリークチェックツールが組み込まれていることに注意してください。ここにある使用説明書:

http://msdn.microsoft.com/en-us/library/974tc9t1(v=vs.100).aspx

GCC / Clangツールチェーンで使用できるmallocのオープンソースの代替品もありますが、直接の経験はありません。Linuxでは、とにかくリーク検出にはValgrindが推奨され、より信頼性の高い方法だと思います。(そして私の経験では、MSVCRTデバッグよりも使いやすいです)。

于 2012-12-24T19:01:21.153 に答える
2

折り返しmallocfree [または]newdelete別の関数で行う以外に、実際には非常に大まかな見積もり以外のものが得られるかどうかは非常に疑わしいです。

問題の1つは、解放されたメモリは、メモリの長い連続したチャンクがある場合にのみ解放できることです。通常発生するのは、ヒープ全体で使用されるメモリの「小さなビット」があり、解放できる大きなチャンクを見つけることができないということです。

これを簡単な方法で修正できる可能性はほとんどありません。

ちなみに、後でさらに負荷がかかると、アプリケーションで50 MBが必要になる可能性があるため、アプリケーションを解放するのは無駄な労力です。

(使用していないメモリが他の目的で必要な場合、それはスワップアウトされ、長時間触れられていないページが最有力候補であるため、システムが他のタスクのためにメモリを使い果たした場合、それでもそのスペースのためにマシンのRAMを再利用するので、無駄にそこに座っているわけではありません-プログラムが使用するRAMの量を把握するために「ps」などを使用できないだけです!)

コメントで示唆されているように、独自のメモリアロケータmmap()を作成して、部分を削除するための「チャンク」を作成することもできます。多くのメモリ割り当てを行うコードのセクションがあり、それらすべてが後で確実に解放されて、別のメモリの塊からすべてを割り当てる場合、すべてが解放されたら、mmapを配置できます。 d領域を「フリーmmapリスト」に戻し、リストが十分に大きい場合は、mmap割り当ての一部を解放します[これは、mmapを何度も呼び出さないようにするためです。munmap再び数ミリ秒後]。ただし、これらのメモリ割り当ての1つをフェンスで囲まれた領域から「エスケープ」させると、アプリケーションがクラッシュする可能性があります(さらに悪いことに、クラッシュすることはありませんが、アプリケーションの他の部分に属するメモリを使用すると、非常に多くのメモリが割り当てられます。あるユーザーが別のユーザー向けのネットワークコンテンツを見るなど、どこかで奇妙な結果になります!)

于 2012-12-24T16:56:09.170 に答える
1

valgrindを使用してメモリリークを見つけます:valgrind ./your_application

メモリを割り当てた場所と解放しなかった場所が一覧表示されます。

Linuxの問題ではないと思いますが、アプリケーションに問題があります。«トップ»でメモリ使用量を監視する場合、非常に正確な使用量を取得することはできません。massif(valgrindのツール)を使用してみてください:valgrind --tool = massif ./your_applicationを使用して、実際のメモリ使用量を確認してください。

C ++でのリークを回避するためのより一般的なルールとして、通常のポインターの代わりにスマートポインターを使用します。また、多くの場合、メモリを「新規」に割り当てる代わりに、RAII(http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization)を使用できます。

于 2012-12-24T16:51:04.300 に答える
1

freeまたはを呼び出すときにOSがメモリを解放することは一般的ではありませんdelete。このメモリは、ランタイムライブラリのヒープマネージャに戻ります。

実際にメモリを解放したい場合は、を使用できますbrk。しかし、それはメモリ管理ワームの非常に大きな缶を開きます。直接電話する場合は、電話brkしない方がよいでしょうmalloc。C ++の場合、オーバーライドnewして直接使用できますbrk

簡単な作業ではありません。

于 2012-12-24T16:52:56.880 に答える
1

最新のdlmalloc()には、mspaceと呼ばれる概念があります(他の人はそれをリージョンと呼びます)。mspaceに対してmalloc()およびfree()を呼び出すことができます。または、mspaceを削除して、mspaceから割り当てられたすべてのメモリを一度に解放することもできます。mspaceを削除すると、プロセスからメモリが解放されます。

接続を使用してmspaceを作成し、そのmspaceから接続用にすべてのメモリを割り当て、接続が閉じたときにmspaceを削除すると、プロセスが大きくなることはありません。

あるmspaceに別のmspaceのメモリを指すポインタがあり、2番目のmspaceを削除すると、言語弁護士は「結果は未定義です」と言います。

于 2012-12-24T17:45:39.230 に答える