2012-11-21 9 views
12

私はコードに次の問題を抱えていました。私はValgrindとgperftoolsを使ってヒープチェックとヒーププロファイリングを行っていました。これらのツールの出力はよく見えるし、私はメモリを失っていないようだ。しかし、私がtopと出力のpsを見ていると、これは基本的にvalgrindとgperftoolsで観測していることを表していないので、私は混乱しています。C++でメモリ使用量を追跡し、メモリ消費量を評価する

  • トップレポート:RES 150M
  • Valgrindの(山塊)レポート:23Mピーク使用
  • gperftoolsヒーププロファイラレポート:ここ

    は数字です22.7Mピーク時の使用

私の質問は今どこにありますか?彼の違いはどこから来たの?私はValgrindでスタックの使用状況を追跡しようとしましたが、成功しませんでした。

いくつかの詳細:

  • プロセスは、基本的に、メモリ記憶
  • リークチェックを実行し、ロードが行われた直後に破断にC APIを介してのMySQLからデータを読み込んで、示しています現在割り当てられている量に合った、144バイトの確定的な喪失と到達可能なもの。
  • ライブラリは複雑なIPCを実行せず、スレッドをいくつか開始するが、スレッドのうちの1つだけが作業を実行中である。
  • ロードされない他の複雑なシステムライブラリIES
  • PSSサイズからは/ proc/PID/smaps RESのTOPでのサイズとPS

に対応報告し、メモリ消費量のこの差はどこから来たあなたは、任意のアイデアを持っていますか?私のプログラムが正しく動作していることをどのように検証できますか?この問題をさらに詳しく調べる方法はありますか?

+1

違いはvalgrind自体に起因する可能性がありますか? –

+1

Valgrindまたはgperftoolsを実行していないときにRESとPSSのサイズを収集しました。 – grundprinzip

+1

'RES - Resident size(kb) タスクが使用していたスワップされていない物理メモリ。'愚かな疑問ですが、free()は常にRESを減らしますか?別の男は、私が思うような同様の問題を抱えています。http://stackoverflow.com/questions/12262146/free-can-not-release-the-mem-and-decrease-the-value-of-res-column-of- top –

答えて

14

最後に私はこの問題を解決することができ、私の発見を喜んで共有します。私の見解から、プログラムのメモリ消費量を評価する最も良いツールは、ValgrindのMassifツールです。ヒープ消費をプロファイルし、詳細な分析を行うことができます。

アプリケーションのヒープをプロファイルするにはvalgrind --tool=massif progを実行してください。mallocなどの一般的なメモリ割り当て機能に関するすべての情報に基本的にアクセスできます。しかし、深く掘り下げるために、私はオプション--pages-as-heap=yesを有効にしました。これは、アンダーレイシステムコールに関する情報さえも報告します。

67 1,284,382,720  978,575,360  978,575,360    0   0 
100.00% (978,575,360B) (page allocation syscalls) mmap/mremap/brk, --alloc-fns, etc. 
->87.28% (854,118,400B) 0x8282419: mmap (syscall-template.S:82) 
| ->84.80% (829,849,600B) 0x821DF7D: _int_malloc (malloc.c:3226) 
| | ->84.36% (825,507,840B) 0x821E49F: _int_memalign (malloc.c:5492) 
| | | ->84.36% (825,507,840B) 0x8220591: memalign (malloc.c:3880) 
| | | ->84.36% (825,507,840B) 0x82217A7: posix_memalign (malloc.c:6315) 
| | |  ->83.37% (815,792,128B) 0x4C74F9B: std::_Rb_tree_node<std::pair<std::string const, unsigned int> >* std::_Rb_tree<std::string, std::pair<std::string const, unsigned int>, std::_Select1st<std::pair<std::string const, unsigned int> >, std::less<std::string>, StrategizedAllocator<std::pair<std::string const, unsigned int>, MemalignStrategy<4096> > >::_M_create_node<std::pair<std::string, unsigned int> >(std::pair<std::string, unsigned int>&&) (MemalignStrategy.h:13) 
| | |  | ->83.37% (815,792,128B) 0x4C7529F: OrderIndifferentDictionary<std::string, MemalignStrategy<4096>, StrategizedAllocator>::addValue(std::string) (stl_tree.h:961) 
| | |  | ->83.37% (815,792,128B) 0x5458DC9: var_to_string(char***, unsigned long, unsigned long, AbstractTable*) (AbstractTable.h:341) 
| | |  |  ->83.37% (815,792,128B) 0x545A466: MySQLInput::load(std::shared_ptr<AbstractTable>, std::vector<std::vector<ColumnMetadata*, std::allocator<ColumnMetadata*> >*, std::allocator<std::vector<ColumnMetadata*, std::allocator<ColumnMetadata*> >*> > const*, Loader::params const&) (MySQLLoader.cpp:161) 
| | |  |  ->83.37% (815,792,128B) 0x54628F2: Loader::load(Loader::params const&) (Loader.cpp:133) 
| | |  |   ->83.37% (815,792,128B) 0x4F6B487: MySQLTableLoad::executePlanOperation() (MySQLTableLoad.cpp:60) 
| | |  |   ->83.37% (815,792,128B) 0x4F8F8F1: _PlanOperation::execute_throws() (PlanOperation.cpp:221) 
| | |  |    ->83.37% (815,792,128B) 0x4F92B08: _PlanOperation::execute() (PlanOperation.cpp:262) 
| | |  |    ->83.37% (815,792,128B) 0x4F92F00: _PlanOperation::operator()() (PlanOperation.cpp:204) 
| | |  |     ->83.37% (815,792,128B) 0x656F9B0: TaskQueue::executeTask() (TaskQueue.cpp:88) 
| | |  |     ->83.37% (815,792,128B) 0x7A70AD6: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.16) 
| | |  |      ->83.37% (815,792,128B) 0x6BAEEFA: start_thread (pthread_create.c:304) 
| | |  |      ->83.37% (815,792,128B) 0x8285F4B: clone (clone.S:112) 
| | |  |       
| | |  ->00.99% (9,715,712B) in 1+ places, all below ms_print's threshold (01.00%) 
| | |  
| | ->00.44% (4,341,760B) in 1+ places, all below ms_print's threshold (01.00%) 

あなたが見ることができるように〜私のメモリ割り当ての85%が単一の分岐から来ている場合、メモリの消費量は、非常に高いので、なぜ質問は以下のようになります。ここでは例として与えられたに私のプロファイリングセッションから何かがあります元のヒーププロファイリングは通常の消費を示しました。この例を見ると、その理由がわかります。割り当てのために、私はposix_memalignを使って割り当てが有用な境界に起こることを確認しました。このアロケータは、外部クラスから内部メンバ変数(この場合はマップ)に渡され、ヒープ割り当てにアロケータを使用します。しかし私が選ぶ境界は私の場合は4096と大きすぎました。つまり、posix_memalignを使用して4bを割り当てることになりますが、正しく整列させるためにシステムがフルページを割り当てます。多くの小さな値を割り当てると、未使用のメモリがたくさん残ってしまいます。このメモリーは、通常のヒープ・プロファイリング・ツールでは報告されません。なぜなら、このメモリーの一部しか割り振らないからです。しかし、システム割り振りルーチンは、より多くを割り振り、残りを隠すでしょう。

この問題を解決するために、私はより小さな境界に切り替えて、メモリオーバーヘッドを大幅に減らすことができました。

Massif & Co.の前で過ごした時間の結論として、このツールを深いプロファイリングに使用することをお勧めします。なぜなら、何が起きているかを非常によく理解していて、簡単にエラーを追跡できるからです。 posix_memalignを使用する場合は状況が異なります。しかし、実際にはほとんどの場合、正常な場合は正常な場合があります。malloc

0

デフォルトでは、Massifはヒープサイズのみを報告します。 TOPはプログラムコード自体が使用するサイズやスタックサイズなど、実際のメモリサイズを報告します。

--stacks=yesオプションを指定して、スタック全体のメモリ使用状況を報告し、画像が変わるかどうかを確認するようにしてください。

+0

上記のようにMassifとスタックサイズをチェックしましたが、スタックサイズは約15kです。 – grundprinzip

1

thisによると、記事ps/topは、実行している唯一のプログラムであれば、プログラムが使用するメモリ量を報告します。たとえば、既にメモリにロードされているSTLなどの共有ライブラリの束を使用すると、プログラムの実行によって割り当てられる実際のメモリの量と、唯一のプロセスである場合に割り当てられるメモリの量との間に差があります。

+0

この記事では、PSSのサイズに関するヒントを入手したので、確認しました。さらに調査すると、メモリ消費量の違いのいくつかは、 'const char *'に 'std :: string'変換に大きなブロックといくつかの奇妙さを割り当てる、malloc() 。 '--pages-as-heap = yes'オプションを指定したValgrindsマジフが多くの助けになりました。 – grundprinzip

+0

私は参照してください。さらなる調査のためのアイデア:プログラム内で割り当てるメモリ量を増やしてください(たとえば、24MB - > 512MB - > 1024MB)。また、未定義のtop/ps出力差が一定のままであるか、または増加するかを観察してください。 – Christian

関連する問題