memusage -
プログラムのメモリー使用量のプロファイルを行う
memusage [
option]...
program [
programoption]...
memusage は、 プログラム
program
のメモリー使用量のプロファイルを行う
bash スクリプトである。
呼び出し元の環境に (
LD_PRELOAD
環境変数を使って)
libmemusage.so
ライブラリをプレロードする。
ld.so(8) を参照。
libmemusage.so
ライブラリは、
malloc(3),
calloc(3),
free(3),
realloc(3)
の呼び出しを横取りし、
メモリー割り当て状況の追跡を行う。
追加で、
mmap(2),
mremap(2),
munmap(2)
を追跡することもできる。
memusage
は収集したデータをテキスト形式で出力することもできるし、
memusagestat(1)
を使って収集したデータをグラフにした
PNG
ファイルを作成することもできる
(以下の
-p
オプションを参照)。
memusage が出力する "Memory usage
summary"
(メモリー使用量概要)
の行には以下のフィールドが含まれる。
- heap total
-
malloc(3)
のすべての呼び出しの
size 引数の合計、
calloc(3)
のすべての呼び出しの引数の積
( nmemb*size)、 mmap(2)
のすべての呼び出しの
length 引数の合計。
realloc(3) と mremap(2)
の場合、
割り当ての新しいサイズが以前のサイズよりも大きい場合、
差分
(新しいサイズから古いサイズを引いた値)
の合計が加算される。
- heap peak
-
malloc(3) の size
引数、 calloc(3) の
nmemb*size の積、 realloc(3)
の size 引数、 mmap(2) の
length 引数、 mremap(2) の
new_size 引数、
の中の最大値。
- stack peak
- 監視される関数の最初の呼び出しが行われる前に、
スタックポインターアドレス
(ベーススタックポインター)
が保存される。
関数のそれぞれの呼び出し後には、
実際のスタックポインターアドレスを読み込み、
ベースポインターアドレスを元に差分を計算する。これらの差分の最大値がスタックのピーク値となる。
この概要行の直後には、
監視対象の各関数の呼び出し回数、
割り当て・割り当て解除された全メモリー量、
失敗した回数がテーブルで表示される。
realloc(3) と
mremap(2)
の場合には、
フィールド "nomove"
でブロックアドレスを変更した再割り当て数を、
フィールド "dec"
でブロックサイズが減少した再割り当て数が追加で表示される。
realloc(3) の場合、
フィールド "free"
でブロックの解放が行われた再割り当て
(サイズが 0
の再割り当て)
の数も追加で表示される。
memusage
が出力するテーブルの
"realloc/total memory"
(再割り当てメモリー/全メモリー)
には、
realloc(3)
を使ってメモリーブロックをその前よりも小さいサイズに再割り当てされた場合は含まれない。
このため、 ("free"
以外の)
すべての「総メモリー」のセルは
"free/total memory"
セルよりも大きくなることがある。
"Histogram for block sizes"
(ブロックサイズのヒストグラム)
は、
メモリー割り当てをバケットサイズ単位に分割した情報である。
-
-n name, --progname=name
- プロファイル対象のプログラムファイル名。
-
-p file, --png=file
- PNG
画像を生成し、 file
に格納する。
-
-d file, --data=file
- バイナリーデータファイルを生成し、
file に格納する。
-
-u, --unbuffered
- 出力バッファーリングを行わない。
-
-b size, --buffer=size
- 出力する前に
size
個のエントリーの収集を行う。
- --no-timer
- スタックポインター値の時間ベースのサンプリング
( SIGPROF)
を無効にする。
-
-m, --mmap
-
mmap(2), mremap(2), munmap(2)
も追跡対象とする。
-
-?, --help
- ヘルプを表示し、終了する。
- --usage
- 簡潔な使用方法を表示して終了する。
-
-V, --version
- バージョン情報を表示して終了する。
- 以下のオプションは画像出力を行う場合にのみ適用される。
-
-t, --time-based
- X 軸の目盛として
(関数呼び出し数ではなく)
時間を使用する。
-
-T, --total
- メモリーの全使用量のグラフも生成する。
-
--title=name
- グラフのタイトルとして
name を使用する。
-
-x size, --x-size=size
- グラフの幅を
size
ピクセルにする。
-
-y size, --y-size=size
- グラフの高さを
size
ピクセルにする。
終了ステータスはプロファイルしたプログラムの終了ステータスと同じになる。
バグ報告については
http://www.gnu.org/software/libc/bugs.html
を参照のこと。
以下の簡単なプログラムは、
ピークに達するまで繰り返しメモリーブロックの再割り当てを行い、
その後ブロックサイズが
0
になるまで繰り返し順に小さなブロックに再割り当てを行う。
このプログラムをコンパイルして以下のコマンドを実行すると、
このプログラムのメモリー使用量がファイル
memusage.png に出力される。
$ memusage --data=memusage.dat ./a.out
...
Memory usage summary: heap total: 45200, heap peak: 6440, stack peak: 224
total calls total memory failed calls
malloc| 1 400 0
realloc| 40 44800 0 (nomove:40, dec:19, free:0)
calloc| 0 0 0
free| 1 440
Histogram for block sizes:
192-207 1 2% ================
...
2192-2207 1 2% ================
2240-2255 2 4% =================================
2832-2847 2 4% =================================
3440-3455 2 4% =================================
4032-4047 2 4% =================================
4640-4655 2 4% =================================
5232-5247 2 4% =================================
5840-5855 2 4% =================================
6432-6447 1 2% ================
$ memusagestat memusage.dat memusage.png
#include <stdio.h>
#include <stdlib.h>
#define CYCLES 20
int
main(int argc, char *argv[])
{
int i, j;
size_t size;
int *p;
size = sizeof(*p) * 100;
printf("malloc: %zu\n", size);
p = malloc(size);
for (i = 0; i < CYCLES; i++) {
if (i < CYCLES / 2)
j = i;
else
j--;
size = sizeof(*p) * (j * 50 + 110);
printf("realloc: %zu\n", size);
p = realloc(p, size);
size = sizeof(*p) * ((j + 1) * 150 + 110);
printf("realloc: %zu\n", size);
p = realloc(p, size);
}
free(p);
exit(EXIT_SUCCESS);
}
memusagestat(1),
mtrace(1),
ld.so(8)
この man ページは Linux
man-pages
プロジェクトのリリース
5.10
の一部である。プロジェクトの説明とバグ報告に関する情報は
https://www.kernel.org/doc/man-pages/
に書かれている。