Linux プロセスが使用する RAM の量を調べるのは簡単なことではありません。共有メモリを考慮する必要がある場合は特にそうです。ありがたいことに、
pmap
コマンドはすべてを理解するのに役立ちます。
メモリマッピング
最新の オペレーティング システム では、各プロセスは独自に割り当てられたメモリ領域または割り当てスペースに存在します。割り当てられた領域の境界は、物理ハードウェア アドレスに直接マッピングされません。オペレーティング システムは、 プロセス ごとに仮想メモリ空間を作成し、仮想メモリを物理メモリにマッピングする抽象化層として機能します。
カーネルはプロセスごとに変換テーブルを保持しており、これには CPU がアクセスします。カーネルが特定の CPU コア で実行されているプロセスを変更すると、プロセスと CPU コアを結び付ける変換テーブルが更新されます。
抽象化の利点
この計画には利点があります。メモリの使用は、ユーザーランドのプロセスごとにある程度カプセル化され、サンドボックス化されます。プロセスは、仮想メモリ アドレスの観点からメモリのみを「認識」します。これは、オペレーティング システムによって与えられたメモリでのみ動作できることを意味します。共有メモリにアクセスできない限り、他のプロセスに割り当てられたメモリについては知りませんし、アクセスすることもできません。
ハードウェアベースの物理メモリを仮想メモリ アドレスに抽象化すると、カーネルは仮想メモリのマッピング先の物理アドレスを変更できるようになります。仮想メモリの領域が指す実際のアドレスを変更することで、メモリをディスクに スワップ できます。また、実際に必要になるまで物理メモリの提供を延期することもできます。
メモリの読み取りまたは書き込み要求が要求どおりに処理される限り、カーネルは適切と判断したマッピング テーブルを自由に操作できます。
RAM オンデマンド
マッピング テーブルと「RAM オンデマンド」の概念により、共有メモリの可能性が広がります。カーネルは、同じものをメモリに複数回ロードすることを避けようとします。たとえば、共有ライブラリをメモリに一度ロードし、それを使用する必要があるさまざまなプロセスにマップします。各プロセスは共有ライブラリに対して独自の一意のアドレスを持ちますが、それらはすべて同じ実際の場所を指します。
メモリの共有領域が書き込み可能な場合、カーネルはコピーオンライトと呼ばれる方式を使用します。 1 つのプロセスが共有メモリに書き込み、そのメモリを共有する他のプロセスが変更を認識しないことになっている場合、書き込みリクエストの時点で共有メモリのコピーが作成されます。
2009 年 12 月にリリースされた Linux カーネル 2.6.32 では、Linux に「Kernel SamePage Merging」と呼ばれる機能が追加されました。これは、Linux が異なるアドレス空間にあるデータの同一領域を検出できることを意味します。一連の 仮想マシンが 1 台のコンピューター上で実行されており、それらの仮想マシンはすべて同じオペレーティング システムを実行していると想像してください。共有メモリ モデルとコピーオンライトを使用すると、ホスト コンピュータのオーバーヘッドを大幅に削減できます。
これらすべてにより、Linux でのメモリ処理が洗練され、可能な限り最適化されます。しかし、その高度な機能により、プロセスを調べてそのメモリ使用量を実際に把握することが困難になります。
pmap ユーティリティ
カーネルは、「/proc」システム情報擬似ファイルシステム内の 2 つの擬似ファイルを通じて、 RAM で実行していることの多くを公開します。プロセスごとに 2 つのファイルがあり、各プロセスのプロセス ID または PID に基づいて名前が付けられています:「/proc/maps」と「/proc//smaps」。
pmap
ツールはこれらのファイルから情報を読み取り、結果をターミナル ウィンドウに表示します。
pmap
使用するときは常に、関心のあるプロセスの PID を指定する必要があることは明らかです。
プロセスIDの確認
プロセスの PID を見つける方法はいくつかあります。これは、例で使用する簡単なプログラムのソース コードです。これは C で書かれています。ターミナル ウィンドウにメッセージを出力し、ユーザーが「Enter」キーを押すのを待つだけです。
#include <stdio.h>
int main(int argc, char *argv[])
{
printf(“How-To Geek テスト プログラム。”);
getc(標準入力);
} // メインの終わり
プログラムは、
gcc
コンパイラーを使用して
pm
という実行可能ファイルにコンパイルされました。
gcc -o pm pm.c
プログラムはユーザーが「Enter」を押すまで待機するため、好きなだけ実行され続けます。
./午後
プログラムが起動し、メッセージを出力し、キーストロークを待ちます。これで PID を検索できるようになりました。
ps
コマンドは、実行中のプロセスを一覧表示します。
-e
(すべてのプロセスを表示) オプションを使用すると、すべてのプロセスが
ps
リストに表示されます。出力を
grep
にパイプし、名前に「pm」を含むエントリをフィルターで除外します。
ps -e | grep午後
これにより、名前のどこかに「pm」が含まれるすべてのエントリがリストされます。
pidof
コマンドを使用すると、より具体的にすることができます。コマンドラインで関心のあるプロセスの名前を
pidof
に指定すると、一致するプロセスの検索が試みられます。一致するものが見つかった場合、
pidof
一致するプロセスの PID を出力します。
ピドフ午後
pidof
メソッドはプロセス名がわかっている場合にはより適切ですが、
ps
メソッドはプロセス名の一部しかわかっていなくても機能します。
pmap の使用
テスト プログラムを実行し、その PID を特定したら、次のように pmap を使用できます。
pmap 40919
プロセスのメモリ マッピングが一覧表示されます。
コマンドの完全な出力は次のとおりです。
40919: ./午後
000056059f06c000 4K r—-午後
000056059f06d000 4K rx– pm
000056059f06e000 4K r—-午後
000056059f06f000 4K r—- 午後
000056059f070000 4K rw— 午後
000056059fc39000 132K rw— [アノン]
00007f97a3edb000 8K rw— [アノン]
00007f97a3edd000 160K r—- libc.so.6
00007f97a3f05000 1616K rx– libc.so.6
00007f97a4099000 352K r—- libc.so.6
00007f97a40f1000 4K —– libc.so.6
00007f97a40f2000 16K r—- libc.so.6
00007f97a40f6000 8K rw— libc.so.6
00007f97a40f8000 60K rw— [アノン]
00007f97a4116000 4K r—- ld-linux-x86-64.so.2
00007f97a4117000 160K rx– ld-linux-x86-64.so.2
00007f97a413f000 40K r—- ld-linux-x86-64.so.2
00007f97a4149000 8K r—- ld-linux-x86-64.so.2
00007f97a414b000 8K rw— ld-linux-x86-64.so.2
00007ffca0e7e000 132K rw— [スタック]
00007ffca0fe1000 16K r—- [アノン]
00007ffca0fe5000 8K rx– [アノン]
ffffffffff600000 4K –x– [ anon ]
合計 2756K
最初の行はプロセス名とその PID です。他の各行は、マップされたメモリ アドレスと、そのアドレスのメモリ量をキロバイト単位で示します。各行の次の 5 文字は、仮想メモリのアクセス許可と呼ばれます。有効な権限は次のとおりです。
- r : マップされたメモリはプロセスから読み取ることができます。
- w : マップされたメモリはプロセスによって書き込むことができます。
- x : プロセスは、マップされたメモリに含まれる任意の命令を実行できます。
- s : マップされたメモリは共有されており、共有メモリに加えられた変更は、メモリを共有しているすべてのプロセスに表示されます。
- R : このマップされたメモリにはスワップ領域の予約はありません。
各行の最後の情報は、マッピングのソースの名前です。これは、プロセス名、ライブラリ名、またはスタックやヒープなどのシステム名です。
拡張ディスプレイ
-x
(拡張) オプションは 2 つの追加列を提供します。
pmap -x 40919
コラムにはタイトルが付けられています。 「アドレス」、「キロバイト」、「モード」、および「マッピング」列についてはすでに説明しました。新しい列は「RSS」および「Dirty」と呼ばれます。
完全な出力は次のとおりです。
40919: ./午後
アドレス キロバイト RSS ダーティ モード マッピング
000056059f06c000 4 4 0 r—- 午後
000056059f06d000 4 4 0 rx– 午後
000056059f06e000 4 4 0 r—- 午後
000056059f06f000 4 4 4 r—-午後
000056059f070000 4 4 4 rw— 午後
000056059fc39000 132 4 4 rw— [アノン]
00007f97a3edb000 8 4 4 rw— [アノン]
00007f97a3edd000 160 160 0 r—- libc.so.6
00007f97a3f05000 1616 788 0 rx– libc.so.6
00007f97a4099000 352 64 0 r—- libc.so.6
00007f97a40f1000 4 0 0 —– libc.so.6
00007f97a40f2000 16 16 16 r—- libc.so.6
00007f97a40f6000 8 8 8 rw— libc.so.6
00007f97a40f8000 60 28 28 rw— [アノン]
00007f97a4116000 4 4 0 r—- ld-linux-x86-64.so.2
00007f97a4117000 160 160 0 rx– ld-linux-x86-64.so.2
00007f97a413f000 40 40 0 r—- ld-linux-x86-64.so.2
00007f97a4149000 8 8 8 r—- ld-linux-x86-64.so.2
00007f97a414b000 8 8 8 rw— ld-linux-x86-64.so.2
00007ffca0e7e000 132 12 12 rw— [スタック]
00007ffca0fe1000 16 0 0 r—- [アノン]
00007ffca0fe5000 8 4 0 rx– [アノン]
ffffffffff600000 4 0 0 –x– [あのん]
—————- ——- ——- ——-
合計 KB 2756 1328 96
- RSS : 常駐セットのサイズです。つまり、現在 RAM 内にあり、スワップアウトされていないメモリの量です。
- Dirty : プロセスとマッピングの開始以降、「ダーティ」メモリが変更されました。
すべて見せて
-X
(拡張以上) は、出力に列を追加します。大文字の「X」に注意してください。
-XX
と呼ばれる別のオプション (
-X
よりもさらに優れたもの) は、
pmap
カーネルから取得できるすべてのものを表示します。
-X
-XX
のサブセットであるため、
-XX
からの出力について説明します。
pmap -XX 40919
出力はターミナル ウィンドウ内でひどく回り込み、事実上解読不能になります。完全な出力は次のとおりです。
40919: ./午後
アドレス Perm Offset デバイス Inode サイズ KernelPageSize MMUPageSize Rss Pss Shared_Clean Shared_Dirty Private_Clean Private_Dirty Referenced Anonymous LazyFree AnonHugePages ShmemPmdMapped FilePmdMapped Shared_Hugetlb Private_Hugetlb Swap SwapPss Locked THPeligible VmFlags マッピング
56059f06c000 r–p 00000000 08:03 393304 4 4 4 4 4 0 0 4 0 4 0 0 0 0 0 0 0 0 0 0 0 rd mr mw me dw sd pm
56059f06d000 r-xp 00001000 08:03 393304 4 4 4 4 4 0 0 4 0 4 0 0 0 0 0 0 0 0 0 0 0 0 rd ex mr mw me dw sd pm
56059f06e000 r–p 00002000 08:03 393304 4 4 4 4 4 0 0 4 0 4 0 0 0 0 0 0 0 0 0 0 0 rd mr mw me dw sd pm
56059f06f000 r–p 00002000 08:03 393304 4 4 4 4 4 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 rd mr mw me dw ac sd pm
56059f070000 rw-p 00003000 08:03 393304 4 4 4 4 4 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 rd wr mr mw me dw ac sd pm
56059fc39000 rw-p 00000000 00:00 0 132 4 4 4 4 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 rd wr mr mw me ac sd [ヒープ]
7f97a3edb000 rw-p 00000000 00:00 0 8 4 4 4 4 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 rd wr mr mw me ac sd
7f97a3edd000 r–p 00000000 08:03 264328 160 4 4 160 4 160 0 0 0 160 0 0 0 0 0 0 0 0 0 0 0 rd mr mw me sd libc.so.6
7f97a3f05000 r-xp 00028000 08:03 264328 1616 4 4 788 32 788 0 0 0 788 0 0 0 0 0 0 0 0 0 0 0 rd ex mr mw me sd libc.so.6
7f97a4099000 r–p 001bc000 08:03 264328 352 4 4 64 1 64 0 0 0 64 0 0 0 0 0 0 0 0 0 0 0 rd mr mw me sd libc.so.6
7f97a40f1000 —p 00214000 08:03 264328 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 mr mw me sd libc.so.6
7f97a40f2000 r–p 00214000 08:03 264328 16 4 4 16 16 0 0 0 16 16 16 0 0 0 0 0 0 0 0 0 0 rd mr mw me ac sd libc.so.6
7f97a40f6000 rw-p 00218000 08:03 264328 8 4 4 8 8 0 0 0 8 8 8 0 0 0 0 0 0 0 0 0 0 rd wr mr mw me ac sd libc.so.6
7f97a40f8000 rw-p 00000000 00:00 0 60 4 4 28 28 0 0 0 28 28 28 0 0 0 0 0 0 0 0 0 0 rd wr mr mw me ac sd
7f97a4116000 r–p 00000000 08:03 264305 4 4 4 4 0 4 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 0 rd mr mw me dw sd ld-linux-x86-64.so.2
7f97a4117000 r-xp 00001000 08:03 264305 160 4 4 160 11 160 0 0 0 160 0 0 0 0 0 0 0 0 0 0 0 rd ex mr mw me dw sd ld-linux-x86-64.so.2
7f97a413f000 r–p 00029000 08:03 264305 40 4 4 40 1 40 0 0 0 40 0 0 0 0 0 0 0 0 0 0 0 rd mr mw me dw sd ld-linux-x86-64.so.2
7f97a4149000 r–p 00032000 08:03 264305 8 4 4 8 8 0 0 0 8 8 8 0 0 0 0 0 0 0 0 0 0 rd mr mw me dw ac sd ld-linux-x86-64.so.2
7f97a414b000 rw-p 00034000 08:03 264305 8 4 4 8 8 0 0 0 8 8 8 0 0 0 0 0 0 0 0 0 0 rd wr mr mw me dw ac sd ld-linux-x86-64.so.2
7ffca0e7e000 rw-p 00000000 00:00 0 132 4 4 12 12 0 0 0 12 12 12 0 0 0 0 0 0 0 0 0 0 rd wr mr mw me gd ac [スタック]
7ffca0fe1000 r–p 00000000 00:00 0 16 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 rd mr pf io de dd sd [vvar]
7ffca0fe5000 r-xp 00000000 00:00 0 8 4 4 4 0 4 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 rd ex mr mw me de sd [vdso]
ffffffffff600000 –xp 00000000 00:00 0 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ex [vsyscall]
==== ============== =========== ==== === =========== == ========== ============= ============= ========== ==== ===== ======== ============= ============== ========= === ============== =============== ==== ======= ====== = ==========
2756 92 92 1328 157 1220 0 12 96 1328 96 0 0 0 0 0 0 0 0 0 0 KB
ここにはたくさんの情報があります。列には次の内容が含まれます。
- Address : このマッピングの開始アドレス。これには仮想メモリのアドレス指定が使用されます。
- Perm : メモリのパーミッション。
- Offset : メモリがファイルベースの場合、ファイル内のこのマッピングのオフセット。
-
Device
: メジャー番号とマイナー番号で指定された Linux デバイス番号。
lsblkコマンドを実行すると 、コンピュータ上のデバイス番号を確認 できます。 - i ノード : マッピングが関連付けられているファイルの i ノード 。たとえば、この例では、これは pm プログラムに関する情報を保持する i ノードである可能性があります。
- サイズ : メモリマップ領域のサイズ。
- KernelPageSize : カーネルによって使用されるページ サイズ。
- MMUPageSize : メモリ管理ユニットによって使用されるページ サイズ。
- Rss : 常駐セットのサイズです。つまり、現在 RAM 内にあり、スワップアウトされていないメモリの量です。
- 追伸 :これは比例シェアサイズです。これは、プライベート共有サイズに加算したものです (共有サイズを共有数で割ったもの)。
- Shared_Clean : マッピングの作成後に変更されていない、他のプロセスと共有されているメモリの量。メモリが共有可能であっても、実際に共有されていない場合はプライベート メモリとみなされます。
- Shared_Dirty : マッピングの作成後に変更された、他のプロセスと共有されるメモリの量。
- Private_Clean : マッピングの作成以来変更されていない、他のプロセスと共有されていないプライベート メモリの量。
- Private_Dirty : マッピングの作成後に変更されたプライベート メモリの量。
- Referenced : 現在参照済みまたはアクセス済みとしてマークされているメモリの量。
- 匿名 : スワップアウト先のデバイスがないメモリ。つまり、ファイルにバックアップされていません。
-
LazyFree
:
MADV_FREEとしてフラグが付けられたページ。これらのページには、書き込まれていない変更が含まれている場合でも、解放して再利用できるようにマークされています。ただし、メモリ マッピングでMADV_FREEが設定された後にその後の変更が発生した場合、MADV_FREEフラグは削除され、変更が書き込まれるまでページは再利用されません。 - AnonHugePages : これらは、ファイルにバックアップされていない「巨大な」メモリ ページ (4 KB を超える) です。
- ShmemPmdMapped : huge ページに関連付けられた共有メモリ。これらは、完全にメモリ内に常駐するファイルシステムによって使用されることもあります。
- FilePmdMapped : ページ中間ディレクトリは、カーネルで使用できるページング スキームの 1 つです。これは、PMD エントリによってポイントされるファイルにバックアップされたページの数です。
- Shared_Hugetlb : 変換ルックアサイド テーブル (TLB) は、ユーザー空間のメモリ位置へのアクセスにかかる時間を最適化するために使用されるメモリ キャッシュです。この数値は、共有巨大メモリ ページに関連付けられた TLB で使用される RAM の量です。
- Private_Hugetlb : この数値は、プライベート ヒュージ メモリ ページに関連付けられた TLB で使用される RAM の量です。
- スワップ : 使用されているスワップの量。
- SwapPss : スワップ比例シェアのサイズ。これは、スワップされたプライベート メモリ ページで構成されるスワップ量に加算されたスワップ量です (共有サイズを共有数で割ったもの)。
- Locked : メモリ マッピングをロックして、オペレーティング システムがヒープ メモリまたはオフヒープ メモリをページアウトしないようにすることができます。
- THPeligible : これは、マッピングが透過的なヒュージ ページを割り当てるのに適格であるかどうかを示すフラグです。 1 は真を意味し、0 は偽を意味します。透過的ヒュージ ページは、大量の RAM を搭載したコンピューターでの TLB ページ検索のオーバーヘッドを軽減するメモリ管理システムです。
- VmFlags : 以下のフラグのリストを参照してください。
- マッピング : マッピングのソースの名前。これは、プロセス名、ライブラリ名、またはスタックやヒープなどのシステム名です。
VmFlags — 仮想メモリ フラグ — は、次のリストのサブセットになります。
- rd : 読めます。
- wr : 書き込み可能。
- 例 : 実行可能ファイル。
- sh : 共有。
- ミスター :読んでもいいよ。
- mw : 書くかも知れません。
- 私 :実行してもいいです。
- ms : 共有するかもしれません。
- gd : スタックセグメントが下方に成長します。
- pf : 純粋なページ フレーム番号の範囲。ページ フレーム番号は、物理メモリ ページのリストです。
- dw : マップされたファイルへの書き込みが無効になりました。
- lo : ページはメモリ内でロックされています。
- io : メモリマップド I/O 領域。
-
sr
: シーケンシャル読み取りアドバイスが提供されます (
madvise()関数によって)。 - rr : ランダム読み取りアドバイスが提供されます。
- dc : プロセスがフォークされている場合は、このメモリ領域をコピーしないでください。
- de : 再マッピング時にこのメモリ領域を拡張しません。
- ac : 地域には責任があります。
- nr : この領域にはスワップ領域が予約されていません。
- ht : 領域は巨大な TLB ページを使用します。
- sf : 同期ページフォルト。
- ar : アーキテクチャ固有のフラグ。
- wf : プロセスがフォークされた場合は、このメモリ領域を消去します。
- dd : このメモリ領域をコア ダンプに含めないでください。
- sd : ソフトダーティフラグ。
- mm : 混合マップ領域。
- hg : 巨大なページのアドバイスフラグ。
- nh : huge page アドバイスフラグはありません。
- mg : マージ可能なアドバイスフラグ。
- bt : ARM64 バイアス温度不安定性保護ページ。
- mt : ARM64 メモリタグ付け拡張タグが有効になります。
- um : Userfaultfd の追跡がありません。
- uw : Userfaultfd wr-protect 追跡。
メモリ管理が複雑になる
そして、データの表から逆算して
実際に何が起こっているのかを理解する
のは困難です。しかし、少なくとも
pmap
全体像を提供してくれるので、何を知るべきかを理解する可能性が最も高くなります。
興味深いことに、サンプル プログラムは 16 KB のバイナリ実行可能ファイルにコンパイルされていますが、ほぼすべてがランタイム ライブラリによって、約 2756 KB のメモリを使用 (または共有) していることに注目してください。
最後の巧妙なトリックは、
pmap
と
pidof
コマンドを一緒に使用して、プロセスの PID を見つけてそれを
pmap
に渡すアクションを 1 つのコマンドに結合できることです。
pmap $(pidof pm)





