Solaris 模块调试器指南

内核内存高速缓存

本节说明如何查找和检查内核内存高速缓存。通过发出 ::kmastat 命令,可以了解系统中的各种 kmem 高速缓存。

> ::kmastat

cache                        buf    buf    buf    memory     alloc alloc

name                        size in use  total    in use   succeed  fail

------------------------- ------ ------ ------ --------- --------- -----

kmem_magazine_1                8     24   1020      8192        24     0

kmem_magazine_3               16    141    510      8192       141     0

kmem_magazine_7               32     96    255      8192        96     0

...

kmem_alloc_8                   8   3614   3751     90112   9834113     0

kmem_alloc_16                 16   2781   3072     98304   8278603     0

kmem_alloc_24                 24    517    612     24576    680537     0

kmem_alloc_32                 32    398    510     24576    903214     0

kmem_alloc_40                 40    482    584     32768    672089     0

...

thread_cache                 368    107    126     49152    669881     0

lwp_cache                    576    107    117     73728       182     0

turnstile_cache               36    149    292     16384    670506     0

cred_cache                    96      6     73      8192   2677787     0

...

如果运行 ::kmastat,则可以了解“正常”系统的信息。 这将有助于发现系统中正在泄漏内存的过大高速缓存。 根据所运行的系统和正在运行的进程数等因素,::kmastat 的结果将有所不同。

列出各种 kmem 高速缓存的另一种方法是使用 ::kmem_cache 命令:

> ::kmem_cache

ADDR     NAME                      FLAG  CFLAG  BUFSIZE  BUFTOTL

70036028 kmem_magazine_1           0020 0e0000        8     1020

700362a8 kmem_magazine_3           0020 0e0000       16      510

70036528 kmem_magazine_7           0020 0e0000       32      255

...

70039428 kmem_alloc_8              020f 000000        8     3751

700396a8 kmem_alloc_16             020f 000000       16     3072

70039928 kmem_alloc_24             020f 000000       24      612

70039ba8 kmem_alloc_32             020f 000000       32      510

7003a028 kmem_alloc_40             020f 000000       40      584

...

此命令非常有用,因为它可将高速缓存名称映射到地址,并为 FLAG 列中的每个高速缓存提供调试标志。 必须要了解的是,分配器对调试功能的选择是基于每个高速缓存从这组标志派生而来的。 这些是在创建高速缓存时与全局 kmem_flags 变量一起设置的。在系统运行的同时设置 kmem_flags 不会影响调试行为,但会影响随后创建的高速缓存(这种情况在引导后很少发生)。

接下来,请直接使用 MDB 的 kmem_cache walker 遍历 kmem 高速缓存的列表:

> ::walk kmem_cache

70036028

700362a8

70036528

700367a8

...

这将产生对应于内核中每个 kmem 高速缓存的指针的列表。 要了解有关特定高速缓存的信息,请应用 kmem_cache 宏:

> 0x70039928$<kmem_cache

0x70039928:     lock

0x70039928:     owner/waiters

                0

0x70039930:     flags           freelist        offset

                20f             707c86a0        24

0x7003993c:     global_alloc    global_free     alloc_fail

                523             0               0

0x70039948:     hash_shift      hash_mask       hash_table

                5               1ff             70444858

0x70039954:     nullslab

0x70039954:     cache           base            next

                70039928        0               702d5de0

0x70039960:     prev            head            tail

                707c86a0        0               0

0x7003996c:     refcnt          chunks

                -1              0

0x70039974:     constructor     destructor      reclaim

                0               0               0

0x70039980:     private         arena           cflags

                0               104444f8        0

0x70039994:     bufsize         align           chunksize

                24              8               40

0x700399a0:     slabsize        color           maxcolor

                8192            24              32

0x700399ac:     slab_create     slab_destroy    buftotal

                3               0               612

0x700399b8:     bufmax          rescale         lookup_depth

                612             1               0

0x700399c4:     kstat           next            prev

                702c8608        70039ba8        700396a8

0x700399d0:     name    kmem_alloc_24

0x700399f0:     bufctl_cache    magazine_cache  magazine_size

                70037ba8        700367a8        15

...

用于调试的重要字段包括 'bufsize'、'flags' 和 'name'。kmem_cache 的名称(在本示例中为 "kmem_alloc_24")指明了它在系统中的用途。 Bufsize 表示此高速缓存中每个缓冲区的大小;在本示例中,高速缓存用于进行大小为 24 或更小的分配。 'flags' 指明了为此高速缓存启用的调试功能。 可以找到在 <sys/kmem_impl.h> 中列出的调试标志。 在本示例中 'flags' 为 0x20f,即 KMF_AUDIT | KMF_DEADBEEF | KMF_REDZONE | KMF_CONTENTS | KMF_HASH。 本文档将在后续几节中说明每个调试功能。

如果有兴趣查看特定高速缓存中的缓冲区,可以直接遍历该高速缓存中已分配和已释放的缓存区:

> 0x70039928::walk kmem

704ba010

702ba008

704ba038

702ba030

...



> 0x70039928::walk freemem

70a9ae50

70a9ae28

704bb730

704bb2f8

...

MDB 提供了一种为 kmem walker 提供高速缓存地址的快捷方式:此方式会为每个 kmem 高速缓存提供特定的 walker,并且 walker 与高速缓存同名。例如:

> ::walk kmem_alloc_24

704ba010

702ba008

704ba038

702ba030

...



> ::walk thread_cache

70b38080

70aac060

705c4020

70aac1e0

...

现在,您已经知道如何迭代内核内存分配器的内部数据结构以及如何检查 kmem_cache 数据结构的最重要成员。