FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

heaptrack を使ってメモリ挙動を調べたメモ

Docker 上で動いている C++ プログラムのメモリ使用量が大きく、挙動も重そうだったので heaptrack を使って確認した。

まずは素直に heaptrack を実行。

heaptrack ./a.out

相対パスを付けないと実行ファイルとして認識されない点に注意。

実行自体は成功し、heaptrack.*.raw.gz が生成されたが、指示通りに interpret すると以下のようなエラーが出た。

failed to parse line: m ...
allocation index out of bounds
Segmentation fault

raw ファイル自体は壊れておらず、gzip -t は通る。 試行錯誤の結果、以下の形でのみ正しく interpret できた。

zcat heaptrack.xxx.raw.gz \
| /usr/local/lib/heaptrack/libexec/heaptrack_interpret \
| gzip -c > heaptrack.xxx.gz

gzip -dc 経由では失敗し、zcat 経由だと成功する。 理由は深追いしていないが、少なくともこの形は安定した。


Windows 上で GUI を確認するために WSL2 + WSLg を使用。

Qt の xcb 依存が不足していると起動しないので以下を追加。

sudo apt install \
  libxkbcommon-x11-0 \
  libxcb-icccm4 \
  libxcb-image0 \
  libxcb-keysyms1 \
  libxcb-render-util0 \
  libxcb-xinerama0

DISPLAY は自動設定されるので手動 export は不要。

heaptrack_gui heaptrack.xxx.gz

で GUI が起動。


最初に目についたのは Temporary Allocations のグラフ。 時間に対してほぼ直線的に増加している。

一見リークのように見えるが、Temporary Allocations なので「確保→解放」が繰り返されているだけ。

つまり、

  • メモリが残り続けているわけではない
  • malloc/free が異常な回数呼ばれている

という状態。


Temporary Allocations を詳細に見ると、以下が突出していた。

gnu_cxx::__sso_string_base::_M_construct<char*>

250 万回以上。

std::string の構築がホットループ内で大量に発生している。

典型的には以下のようなコードが原因になる。

std::string s = some_cstr;
log << "value=" << x;

SSO があっても、一時生成や連結では allocation が発生する。

ここは

  • string_view 化
  • reserve + 再利用
  • ログの抑制

で大きく改善できる。


次に Consumed(常駐メモリ)を確認。

ピーク時の最大寄与は以下。

std::vector<...>
約 4.7MB

Temporary ではなく、実行中ずっと保持されているデータ構造。

  • vector が grow し続けている
  • clear されない
  • 設計上の常駐データ

という挙動。

これはリークではなく仕様だが、

  • 本当に全期間保持が必要か
  • フェーズ境界で clear できないか
  • reserve が適切か

は検討の余地あり。