Linuxのメモリ管理と関連ツール

IT

CPUと同様にメモリもスマホやパソコンに搭載されており、ほぼ毎日利用しているかと思います。

そこでアンドロイドなどを含むLinuxでメモリがどのように管理されているか簡単にご紹介していきます。

メモリアロケータ

下の図は、ユーザーレベルおよびカーネルレベルのソフトウェアで一般的に使用されるメモリ割り当てシステムを示しています。メモリ割り当てにlibcという標準 C ライブラリを使用するプロセスの場合、メモリはヒープと呼ばれるプロセスの仮想アドレス空間の動的セグメントに格納されます。

libcは、malloc()やfree()などのメモリ割り当て用の関数を提供しています。メモリが解放されると、libcはその場所を追跡し、その場所情報を使用して後続のmalloc()を実行できます。 libcは、使用可能なメモリがない場合にのみ、ヒープのサイズを拡張します。これはすべて仮想メモリであり、実際の物理メモリではないため、libcがヒープのサイズを縮小することはありません。

カーネルとプロセッサは、仮想メモリを物理メモリにマッピングする役割を果たします。効率を上げるために、メモリマッピングはページと呼ばれるメモリのグループで作成されます。

4キロバイトが一般的ですが、ほとんどのプロセッサはより大きなサイズもサポートしています。これはLinuxでは巨大な(Huge)ページと呼んでいます。カーネルは、効率のために各DRAMグループとCPUに対して維持する、独自の空きリストからの物理メモリページ要求を処理できます。カーネル独自のソフトウェアも、通常はスラブアロケータなどのカーネルアロケータを介して、これらの空きリストのメモリも消費します。

Source: BPF Performance Tools

一般的なユーザーメモリページのライフサイクルを図2に示しています。また、次のステップをたどります。

図2 Source: BPF Performance Tools

1.アプリケーションは、メモリの割り当て要求(libc malloc()など)から始まります。

2.割り当ては、独自の空きリストからメモリ要求を処理するか、対応するために仮想メモリを拡張する必要がある場合があります。割り当てライブラリに応じて、次のいずれかになります。

  a. brk()syscallを呼び出し、ヒープメモリを割り当てに使用して、ヒープのサイズを拡張します。

  b. mmap()システムコールを介して新しいメモリセグメントを作成します。

3.しばらくして、アプリケーションは、ストアおよびロード命令を介して割り当てられたメモリ範囲を使用しようとします。これには、仮想アドレスから物理アドレスへの変換のためにプロセッサメモリ管理ユニット(MMU)を呼び出すことが含まれます。物理メモリがマップされていない仮想アドレス空間上のページにアクセスしたときに、ページフォールトと呼ばれるMMUエラーが発生します。

4.ページフォールトはカーネルによって処理されます。カーネルは、物理メモリの空きリストから仮想メモリへのマッピングを確立し、後で検索するためにこのマッピングをMMUに通知します。プロセスで使用されている物理メモリの量は、常駐セットサイズ(RSS)と呼ばれます。

5.システムのメモリ需要が多すぎると、カーネルページアウトデーモン(kswapd)が解放するメモリページを探す場合があります。 3種類のメモリのいずれかを解放します。

  a. ディスクから読み取られ、変更されていないファイルシステムページ:これらはすぐに解放され、必要に応じて簡単に再読み取りできます。これらのページは、アプリケーションで実行可能なテキスト、データ、およびファイルシステムのメタデータです。

  b. 変更されたファイルシステムページ:これらは「ダーティ(Dirty)」であり、解放する前にディスクに書き込む必要があります。

  c. アプリケーションメモリのページ:ファイルの出所がないため、匿名メモリと呼ばれます。スワップデバイスが使用されている場合、これらは最初にスワップデバイスに保存することで解放できます。このスワップデバイスへのページの書き込みは、スワッピングと呼ばれます。

ページアウト デーモン

ページアウトデーモン(kswapd)は定期的にアクティブ化され、解放するメモリを検索して非アクティブページとアクティブページのLRU(Least Recently Used)リストをスキャンします。図3に示すように、空きメモリが低いしきい値(low pages)を超えるとウェイクアップされ、高いしきい値(high pages)を超えるとスリープ状態に戻ります。

LRUとは、「最も過去に使用された」の意で、過去に参照されてから最も時間が経ったデータを破棄し、新規のデータと置換するために利用されます。

図3 Source: BPF Performance Tools

kswapdはバックグラウンドでページアウトを調整します。

調整可能な最小ページしきい値(min pages)を超え、kswapdが十分な速度でメモリを解放できない場合は、直接再利用されます。これは、割り当てを満たすためにメモリを解放するフォアグラウンドモードです。このモードでは、割り当てはブロック(ストール)し、ページが解放されるのを同期的に待機します。

直接再利用は、カーネルモジュールシュリンク関数を呼び出すことができます。これらは、カーネルスラブキャッシュを含むキャッシュに保持されていた可能性のあるメモリを解放します。

基本ツール

基本的なツールを使ってメモリに関する調査をはじめてみましょう。

dmesg

Out-of-memory killerなどの情報はシステムログに記載されるので、はじめにdmesgを実行して結果をチェックするといいでしょう。

swapon

スワップデバイスの設定やどれぐらい利用されているか確認できます。
次の例では、2Gバイトのスワップパーティションがあり、そのうち169.3Mバイト利用していることが確認できます。

$ swapon
NAME TYPE            SIZE USED  PRIO
/dev/dm-1 partition    2G 169.3M -2

このように使用されている場合には、vmstatのsiやsoのコラムでもアクティブな情報を確認できます。

$ vmstat
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 2  0 171008 236324   1048 618388    1    7   133    21   48   66  1  0 99  0  0

slabtop

slabtopは、リアルタイムに詳細なカーネル slab キャッシュ情報を表示します。

-s cオプションによって、キャッシュのサイズでソートすることができます。

ここでは、inode_cacheが14MByteの利用が確認できます。

# slabtop -s c
Active / Total Objects (% used)    : 1662948 / 1706740 (97.4%)
 Active / Total Slabs (% used)      : 24176 / 24176 (100.0%)
 Active / Total Caches (% used)     : 101 / 150 (67.3%)
 Active / Total Size (% used)       : 139079.61K / 148925.00K (93.4%)
 Minimum / Average / Maximum Object : 0.01K / 0.09K / 14.75K

  OBJS ACTIVE  USE OBJ SIZE  SLABS OBJ/SLAB CACHE SIZE NAME                   
 21624  20688  95%    0.64K   1802	 12     14416K inode_cache
 55590  54806  98%    0.23K   3270	 17     13080K vm_area_struct
 11145   8855  79%    1.06K    743	 15     11888K xfs_inode
 50232  41131  81%    0.19K   2392	 21	 9568K dentry
297728 292810  98%    0.03K   2326	128	 9304K kmalloc-32
392530 392530 100%    0.02K   2309	170	 9236K avtab_node
  2088   2075  99%    4.00K    261        8	 8352K kmalloc-4k
 ...

free

freeコマンドでシステム全体のメモリ使用量を確認できます。とくに、利用されていないfreeコラムより、利用可能なavailableコラムを確認するといいでしょう。また、-wオプションをつけると、buffersとcacheを分て表示できます。

$free -m
     total used   free shared buff/cache available
Mem: 1818   983    232      8        602       667
Swap: 2047 167 1880

$ free -m -w
              total        used        free      shared     buffers       cache   available
Mem:           1818         982         230           8           1         603         667
Swap:          2047         167        1880

buffersは、カーネルバッファに利用されているメモリです。

cacheは、ページキャッシュやスラブに利用されているメモリです。

buffersとcacheの違いは、何でしょうか?

ページキャッシュはファイルシステムに対するキャッシュであり、ファイル単位でアクセスするときに使用されるキャッシュです。例えば、ファイルへデータを書き込んだときは、ページキャッシュにデータが残されるため、次回の読み込み時には HDD にアクセスすることなくデータを利用できます。

もうひとつのバッファキャッシュはブロックデバイスを直接アクセスするときに使用されるキャッシュです。

ps

プロセス毎のメモリ使用量を確認できます。とくに、つぎの3つに注目しましょう。

%MEM このプロセスによって利用されている物理メモリのパーセント
VSZ 仮想メモリのサイズ(kiloBytes)
RSS このプロセスによって使用されている物理メモリ(kiloBytes)
$ ps aux
USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root           1  0.0  0.5 245956 10040 ?        Ss   11:38   0:02 /usr/lib/systemd/systemd --switched-root --system --deserialize 17
root           2  0.0  0.0      0     0 ?        S    11:38   0:00 [kthreadd]
root           3  0.0  0.0      0     0 ?        I<   11:38   0:00 [rcu_gp]
root           4  0.0  0.0      0     0 ?        I<   11:38   0:00 [rcu_par_gp]
....

pmap

データやプログラムがどこのメモリのアドレス空間に格納されているかを知ることができるツールです。-xオプションをつけることによって、Dirtyページという、メモリ上にあってこれからディスクに書き込まれるべきデータの容量(キロバイト)を表示できます。

# pmap -x 3027
3027:   sshd: root@pts/1                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
Address           Kbytes     RSS   Dirty Mode  Mapping
000055d928721000     820     656       0 r-x-- sshd
000055d9289ee000      16      16      16 r---- sshd
000055d9289f2000       4       4       4 rw--- sshd
000055d9289f3000      16      16      16 rw---   [ anon ]
000055d929f65000     396     356     356 rw---   [ anon ]
00007fb23a9b2000     840     484       0 r-x-- libnss_systemd.so.2
00007fb23aa84000    2048       0       0 ----- libnss_systemd.so.2
...

vmstat

1秒ごとにシステムのメモリやスワップの使用状況を確認できます。siはスワップインで、soはスワップアウトです。スワップインとは、スワップアウトによって一時的にハードディスクへ退避していたデータをメモリ上に戻すことです。スワップアウトとは、実メモリの空き領域が不足した場合に、メモリ上のデータを一時的にハードディスクへ退避させることです。

# vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 2  0 171008 227108   1048 623424    1    6   117    18   46   64  1  0 99  0  0
 0  0 171008 226652   1048 623424    0    0     0     0  133  137  0  1 99  0  0
 0  0 171008 226652   1048 623424    0    0     0     0   59  100  0  0 100  0  0
 0  0 171008 226652   1048 623424    0    0     0     0   75   97  0  1 100  0  0
 0  0 171008 226652   1048 623424    0    0     0     0   59   93  0  0 100  0  0
^C

sar

sarを使ってCPU、メモリ、I/O、ネットワークの通信状況など確認できますが、ここでは-Bオプションを使って、ページングについて調べてみます。

$ sar -B 1
Linux 5.13.6-200.fc34.x86_64 (localhost.localdomain) 	10/06/21 	_x86_64_	(8 CPU)

17:15:01     pgpgin/s pgpgout/s   fault/s  majflt/s  pgfree/s pgscank/s pgscand/s pgsteal/s    %vmeff
17:15:02         0.00      0.00   1337.00      0.00   2759.00      0.00      0.00      0.00      0.00
17:15:03         0.00      0.00     97.00      0.00   2808.00      0.00      0.00      0.00      0.00
17:15:04         0.00      0.00    370.00      0.00   3197.00      0.00      0.00      0.00      0.00
17:15:05         0.00     92.00    671.00      0.00   1307.00      0.00      0.00      0.00      0.00

ページフォルトが1337回/秒発生していることがわかります。ページフォールト (page fault) とは、プログラム(プロセス)がアクセスしようとした仮想メモリ領域(ページ)が物理メモリ上に無く、ストレージに退避していることが分かったときに発生する例外あるいは割り込み処理です。

pgscank/s: 1秒あたりにkswapdデーモンによってスキャンされたページ数

pgscand/s: 1秒あたりに直接スキャンされたページ数

上記2つ項目が0なので、メモリがいっぱいいっぱい使われていないことがわかります。

valgrind

valgrindを利用することによって、メモリリークを発見することができます。

プログラムのコンパイル時に-gオプションをつけることにより、何行目でメモリ解放に問題があるのかを指摘することができます。例えば、つぎのようなプログラムがあるとします。

#include <stdio.h>
#include <stdlib.h>

void get_mem()
{
char *ptr = malloc(7); 
}

int main(void)
{
 char *ptr1, *ptr2;
 int i;
 ptr1 = (char *) malloc(10);
 ptr2 = (char *) malloc(10);
 ptr2 = ptr1;
 free(ptr2);
 free(ptr1);

 for(i=0; i<2; i++) {
 get_mem();
 }
}

このプログラムにvalgrindを使って、どこが、どれだけリークしているのか確認してみます。

# gcc -g mem_leak.c -o mem_leak
# valgrind --tool=memcheck ./mem_leak 
==19909== Memcheck, a memory error detector
==19909== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==19909== Using Valgrind-3.16.0 and LibVEX; rerun with -h for copyright info
==19909== Command: ./mem_leak
==19909== 
==19909== Invalid free() / delete / delete[] / realloc()
==19909==    at 0x4C3210C: free (vg_replace_malloc.c:538)
==19909==    by 0x400632: main (mem_leak.c:17)
==19909==  Address 0x5200040 is 0 bytes inside a block of size 10 free'd
==19909==    at 0x4C3210C: free (vg_replace_malloc.c:538)
==19909==    by 0x400626: main (mem_leak.c:16)
==19909==  Block was alloc'd at
==19909==    at 0x4C30F0B: malloc (vg_replace_malloc.c:307)
==19909==    by 0x400600: main (mem_leak.c:13)
==19909== 
==19909== 
==19909== HEAP SUMMARY:
==19909==     in use at exit: 24 bytes in 3 blocks
==19909==   total heap usage: 4 allocs, 2 frees, 34 bytes allocated
==19909== 
==19909== LEAK SUMMARY:
==19909==    definitely lost: 24 bytes in 3 blocks
==19909==    indirectly lost: 0 bytes in 0 blocks
==19909==      possibly lost: 0 bytes in 0 blocks
==19909==    still reachable: 0 bytes in 0 blocks
==19909==         suppressed: 0 bytes in 0 blocks
==19909== Rerun with --leak-check=full to see details of leaked memory
==19909== 
==19909== For lists of detected and suppressed errors, rerun with: -s
==19909== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

24バイトメモリリークが発生していることがわかります。

具体的には、15行目の「ptr2 = ptr1;」によって、ptr2が指していたアドレスが失われ、10バイトのメモリリークが発生します。また、20行目のget_mem()では、7バイトの確保が2回されますが、いづれも解放されないため14バイトのメモリリークが発生します。つまり、合計で24バイトのメモリリークが発生します。

perf

perfを利用することによってハードウェアベースの監視をすることができます。

主に2つのモードが利用されます。1つは、カウンティングと呼ばれるイベントの発生回数を数えるモードです。もう1つは、サンプリングと呼ばれ、ある一定回数のイベント発生が起こるたびにサンプルを記録するモードです。

ここでは、1秒ごとにLLC(Last Level Cache)と呼ばれるCPUから見て一番遠いキャッシュメモリのロードとミスを観測してみます。インテルのチップですと、通常L3キャッシュを指します。

# perf stat -e LLC-loads,LLC-load-misses -a -I 1000
#           time             counts unit events
     1.001025442         47,772,400      LLC-loads                                                   
     1.001025442          3,060,178      LLC-load-misses           #    6.41% of all LL-cache accesses
     2.001924838         46,257,102      LLC-loads                                                   
     2.001924838          3,392,702      LLC-load-misses           #    7.33% of all LL-cache accesses

上記の例ですと、47,772,400回LLCからロードがあり、そのうち3,060,178回LLCのロードミスが発生しています。つまり、約6.41%メインメモリにアクセスがあったこと指します。

つぎに、サンプリングモードでL1やL3のキャッシュミスを監察してみましょう。

# perf record -e L1-dcache-load-misses  -a
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 2.091 MB perf.data (8642 samples) ]

# perf report -n --stdio
# To display the perf.data header info, please use --header/--header-only options.
#
#
# Total Lost Samples: 0
#
# Samples: 8K of event 'L1-dcache-load-misses'
# Event count (approx.): 38987666
#
# Overhead       Samples  Command          Shared Object                         Symbol                                              >
# ........  ............  ...............  ....................................  ....................................................>
#
    12.83%            79  sssd_kcm         libc-2.33.so                          [.] __memset_avx2_erms
     2.21%           288  swapper          [kernel.kallsyms]                     [k] mwait_idle_with_hints.constprop.0
     1.26%            85  pipewire-pulse   libspa-audioconvert.so                [.] 0x0000000000057c79
     1.09%            74  pipewire-pulse   libspa-audioconvert.so                [.] 0x0000000000057c86
     1.02%           125  swapper          [kernel.kallsyms]                     [k] psi_group_change
     0.79%            48  gnome-shell      libglib-2.0.so.0.6800.2               [.] g_main_context_check
     0.77%            96  swapper          [kernel.kallsyms]                     [k] __schedule
     0.72%            46  gnome-shell      libglib-2.0.so.0.6800.2               [.] g_source_ref
...


# perf record -e LLC-load-misses  -a
^C[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 1.956 MB perf.data (6170 samples) ]

# perf report -n --stdio
# To display the perf.data header info, please use --header/--header-only options.
#
#
# Total Lost Samples: 0
#
# Samples: 6K of event 'LLC-load-misses'
# Event count (approx.): 7799539
#
# Overhead       Samples  Command          Shared Object                         Symbol                                              >
# ........  ............  ...............  ....................................  ....................................................>
#
     3.31%           120  pipewire-pulse   libspa-audioconvert.so                [.] 0x0000000000057c86
     2.57%            79  pipewire-pulse   libspa-audioconvert.so                [.] 0x0000000000057c79
     1.67%            81  gnome-shell      libglib-2.0.so.0.6800.2               [.] g_main_context_check
     1.24%            43  pipewire-pulse   libspa-audioconvert.so                [.] 0x0000000000057c6e
     1.05%            39  pipewire-pulse   libspa-audioconvert.so                [.] 0x0000000000057cd5
     0.95%            77  swapper          [kernel.kallsyms]                     [k] perf_event_task_tick
     0.93%            67  swapper          [kernel.kallsyms]                     [k] psi_group_change
     0.89%            27  pipewire-pulse   libspa-audioconvert.so                [.] 0x0000000000057c8f
     0.83%            62  swapper          [kernel.kallsyms]                     [k] __schedule
     0.74%            34  gnome-shell      libglib-2.0.so.0.6800.2               [.] g_source_ref
     0.72%            55  swapper          [kernel.kallsyms]                     [k] __update_load_avg_cfs_rq
     0.69%            45  swapper          [kernel.kallsyms]                     [k] timerqueue_add

BPF ツール

基本ツールでもある程度の情報を取得できますが、メモリ関連のBPF ツールを使ってもう少し詳細を確認してみましょう。

oomkill

oomkillツールを実行するとout-of-memoryのイベントをトレースでき、また同時に到達したページサイズとロードアベレージも出力します。

# /usr/share/bcc/tools/oomkill
Tracing OOM kills... Ctrl-C to stop.

15:24:39 Triggered by PID 1055 ("tuned"), OOM kill of PID 5728 ("oom-test"), 989864 pages, loadavg: 0.81 0.18 0.06 3/641 5729

ここでは、oom-test.cというプログラムを実行し、意図的にOOMを再現させています。

malloc(1<<20)によって、2進数で表記された1を左へ20ビット桁移動しています。「<<」が左シフト演算子です。つまり1MiBつづOOMが発生するまでメモリ確保していきます。

メビバイト(MiB)とは2の20乗バイトです。

ん?と思った方へ、少し補足します。

ビットは、0か1が入る箱です。このビットが8つ集まったものがバイト。

キロバイトは、10の3乗バイトです。けれど、コンピュータにとっては0と1で表す2進数で2の10乗である1024のほうがキリがいいんです。

そこを正確に区別するために、1キロバイト(KB)=1,000バイト、1キビバイト(KiB)=1,024バイトと区別します。

メガは、10の6乗で、百万を表します。一方、1メビバイト(MiB)は、2の20乗バイト =1,024キロバイト = 1,048,576バイトです。

#include <stdio.h>
#include <stdlib.h>

int main (void) 
{  
	int n = 0;  

         while (1) {  
		if (malloc(1<<20) == NULL) {  
                         printf("malloc failure after %d MiB\n", n);  
                         return 0;  
                 }	
                 printf ("got %d MiB\n", ++n);  
         }  
}  
# gcc oom-test.c  -o oom-test
# ./oom-test 
...
got 449367 MiB
got 449368 MiB
got 449369 MiB
got 449370 MiB
Killed

上記のように、oom-testを実行すると、dmesgでもOOMを次のように確認できます。

[14961.626074] oom-kill:constraint=CONSTRAINT_NONE,nodemask=(null),cpuset=/,mems_allowed=0,global_oom,task_memcg=/user.slice/user-0.slice/session-6.scope,task=oom-test,pid=5728,uid=0
[14961.626084] Out of memory: Killed process 5728 (oom-test) total-vm:458409016kB, anon-rss:650320kB, file-rss:4kB, shmem-rss:0kB, UID:0
[14961.891704] oom_reaper: reaped process 5728 (oom-test), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB

memleak

memleakというツールを使うと、メモリの確保と解放をデフォルトで5秒間隔で表示できます。

例えば、bashのメモリ確保や解放を表示してみます。

# /usr/share/bcc/tools/memleak -p 2288
Attaching to pid 2288, Ctrl+C to quit.
[18:37:25] Top 10 stacks with outstanding allocations:
	77 bytes in 1 allocations from stack
		xrealloc+0x17 [bash]
	323 bytes in 18 allocations from stack
		xmalloc+0x12 [bash]

memleakだけでは、実際にリークしているかは判断できませんので、valgrindを利用したほうがいいでしょう。

また-pオプションを付けないと、カーネルのメモリ確保を表示します。

# /usr/share/bcc/tools/memleak 
Attaching to kernel allocators, Ctrl+C to quit.
[18:44:10] Top 10 stacks with outstanding allocations:
	1024 bytes in 4 allocations from stack
		kmem_cache_alloc+0x139 [kernel]
		kmem_cache_alloc+0x139 [kernel]
		__alloc_file+0x2a [kernel]
		alloc_empty_file+0x43 [kernel]
		alloc_file+0x2b [kernel]
		anon_inode_getfile+0xd2 [kernel]
		anon_inode_getfd+0x35 [kernel]
		bpf_prog_load+0x408 [kernel]
		__do_sys_bpf+0x584 [kernel]
		do_syscall_64+0x5b [kernel]
		entry_SYSCALL_64_after_hwframe+0x65 [kernel]

trace

traceを利用して、システムコールの呼出しをシステム全体でトレースできます。

例えばmmap() をトレースすることにより、新しいマッピングを呼び出し元プロセスの仮想アドレス空間に作成するイベントを確認できます。

# /usr/share/bcc/tools/trace -U t:syscalls:sys_enter_mmap
PID     TID     COMM            FUNC             
13129   13129   date            sys_enter_mmap   
        b'[unknown]'

1682    1682    gnome-shell     sys_enter_mmap   
        b'mmap64+0x47 [libc-2.28.so]'

1682    1712    llvmpipe-0      sys_enter_mmap   
        b'mmap64+0x47 [libc-2.28.so]'

その他、brk()をトレースするこにより、プロセスへのメモリの割り当てや解放イベントも確認できます。

brk() は プログラムブレーク (program break) の場所を変更します。 プログラムブレークはプロセスのデータセグメント (data segment) の 末尾を示します。プログラムブレークを増やすということは、そのプロセスへの メモリーを割り当てる効果があり、 プログラムブレークを減らすということは、メモリーを解放するということになります。

# /usr/share/bcc/tools/trace -U t:syscalls:sys_enter_brk
PID     TID     COMM            FUNC             
13450   13450   awk             sys_enter_brk    
        b'brk+0xb [ld-2.28.so]'

13456   13456   sleep           sys_enter_brk    
        b'brk+0xb [ld-2.28.so]'

page faultもtraceを利用して、簡単に確認することができます。

# /usr/share/bcc/tools/trace -U t:exceptions:page_fault_user
PID     TID     COMM            FUNC             
2288    2288    bash            page_fault_user  
        b'[unknown] [bash]'

2288    2288    bash            page_fault_user  
        b'__libc_fork+0x137 [libc-2.28.so]'

2288    2288    bash            page_fault_user  
        b'make_child+0x42b [bash]'

2288    2288    bash            page_fault_user  
        b'__libc_malloc+0x139 [libc-2.28.so]'

# /usr/share/bcc/tools/trace t:exceptions:page_fault_kernel
PID     TID     COMM            FUNC             
933     933     ksmtuned        page_fault_kernel 
933     933     ksmtuned        page_fault_kernel 
933     933     ksmtuned        page_fault_kernel 
16729   16729   ksmtuned        page_fault_kernel 
16730   16730   ksmtuned        page_fault_kernel 
16730   16730   awk             page_fault_kernel 
16730   16730   awk             page_fault_kernel

コメント

タイトルとURLをコピーしました