寻找内核空间里的内存大户——扩展命令 !ndx.slab详解

实现原理

从Linux内核的全局变量slab_caches获取链表的头地址,进行遍历。
示例:
ffffffff9ce6d6f0 t slab_caches_to_rcu_destroy_workfn
ffffffff9e2eab40 d slab_caches_to_rcu_destroy_work
ffffffff9e2eab60 d slab_caches_to_rcu_destroy
ffffffff9e2eaba0 D slab_caches
得到kmem_cache结构体的信息。

(图片所示信息在NDB中输入dt lk!kmem_cache就能查看,缺少内核信息文件解决方法见下文)

此结构体是用来管理slab的结构体,每一个kmem_cache结构体对应描述的一段内存就是一个slab缓存池。slub分配器将从伙伴系统得到的连续内存平均分成若干大小相等的object(对象)进行管理。
其中的一些信息:

struct kmem_cache {
    struct kmem_cache_cpu __percpu *cpu_slab;
    /* Used for retriving partial slabs etc */
    slab_flags_t flags;
    unsigned long min_partial;
    int size;             /* The size of an object including meta data */
    int object_size;     /* The size of an object without meta data */
    int offset;           /* Free pointer offset. */
#ifdef CONFIG_SLUB_CPU_PARTIAL
    int cpu_partial;      /* Number of per cpu partial objects to keep around */
#endif
    struct kmem_cache_order_objects oo;
    /* Allocation and freeing of slabs */
    struct kmem_cache_order_objects max;
    struct kmem_cache_order_objects min;
    gfp_t allocflags;    /* gfp flags to use on each alloc */
    int refcount;         /* Refcount for slab cache destroy */
    void (*ctor)(void *);
    int inuse;            /* Offset to metadata */
    int align;            /* Alignment */
    int reserved;         /* Reserved bytes at the end of slabs */
    const char *name;    /* Name (only for display!) */
    unsigned int useroffset;/* Usercopy region offset */
    unsigned int usersize;  /* Usercopy region size */
    struct list_head list;  /* List of slab caches */
    struct kmem_cache_node *node[MAX_NUMNODES];
};
  • cpu_slab:一个per cpu变量。相当于一个本地内存缓存池,当分配内存的时候优先从本地cpu分配内存。
  • flags:object分配掩码,例如经常使用的SLAB_HWCACHE_ALIGN标志位,代表创建的kmem_cache管理的object按照硬件cache 对齐。
  • name:供显示使用的文件名字。
  • size:分配的object size。
  • object_size:实际的object size,就是创建kmem_cache时候传递进来的参数。和size的关系就是,size是各种地址对齐之后的大小。因此,size要大于等于object_size。
  • oo:低16位代表一个slab中所有object的数量,高16位代表一个slab管理的page数量。
  • list:所有的slab都会挂入链表,因此遍历此信息就可以得到所有slab信息。
  • inuse:object_size对齐之后的大小。
  • align:字节对齐大小。

得到所有的信息后输出汇总。

具体使用

  • 直接输入!ndx.slab

如果出现如上图所示的提示,那么缺少加载内核信息的文件。
文件示例如下:

输入.sympath 文件全路径,然后再输入.reload即可。
例如输入
.sympath d:\wucheng,然后输入.reload加载此文件夹即可。
您可以输入lm查看

说明加载成功了。

  • 再次输入!ndx.slab
    会逐个输出slab分配器状态,并最后按照总数排序输出(从大到小排序)。需要大约一分半时间读取。
    如下图所示
    开始
    当逐个输出slab分配器结束后,进行名字分类汇总,从小到大排序。这样我们就能看到谁占用了较多的内存了。

    其中
  • total_obj=size X num_obj
  • num_obj=objperslab X slab数目


比如:
图中的ext4_inode_cache,我们能看到它占用的空间很大,虽然size不是很大但是其object的数目很大,因而占用内存也很大。它占用的slab数量是1350/27=50,也就是说上图中显示的kmem_cache中有50个都用来存储ext4_inode_cache。
向上翻找也能找到很多,
比如


等等。

作者:YuQing  创建时间:2022-07-19 10:42
最后编辑:YuQing  更新时间:2024-04-26 11:16