如何诊断SLUB问题【转】

2021年11月23日 阅读数:4
这篇文章主要向大家介绍如何诊断SLUB问题【转】,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

转自:http://linuxperf.com/?p=184node

前文中,咱们介绍了在RHEL6及较早的kernel上诊断slab泄漏问题的两种方法,能够说至关麻烦了,这是由于之前的slab没有提供原生的故障诊断机制。Linux kernel自2.6.23以后采用的Slub自带了故障诊断机制,就方便不少,然而习惯上仍然把slub称做slab。如何判断你的系统kernel是否在用slub呢?仅从kernel版本号是看不许的,好比RHEL6的kernel版本2.6.x仍然在使用slab,从RHEL7才开始采用Slub。有一个简单的判断方法,就是看是否存在/sys/kernel/slab目录,有就是slub,没有就是slab。linux

Slub的debug机制

了解slub的debug机制以前,先要弄清楚可能会出现哪些问题,不管是slab仍是slub,问题无非是如下几类:git

  • 内存泄露(leak),alloc以后忘了free,致使内存占用不断增加;
  • 越界(overrun),访问了alloc分配的区域以外的内存,覆盖了不属于本身的数据;
  • 使用已经释放的内存(use after free),正常状况下,已经被free释放的内存是不该该再被读写的,不然就意味着程序有bug;
  • 使用未经初始化的数据(use uninitialised bytes),缺省模式下alloc分配的内存是不被初始化的,内存值是随机的,直接使用的话后果多是灾难性的。

Slub提供了red zone和poisoning等debug机制来检测以上问题。xcode

  • Red zone来自于橄榄球术语,是指球场底线附近的区域,slub经过在每个对象后面额外添加一块red zone区域来帮助检测越界(overrun)问题,在red zone里填充了特征字符,若是代码访问到了red zone就意味着越界了。
  • Poisoning是经过往slub对象中填充特征字符的方式来检测use-after-free、use-uninitialised等问题,好比在分配slub对象时填充0x5a,在释放时填充0x6b,而后debug代码检查时若是看到本该是0x6b的位置变成了别的内容,就多是发生了use-after-free,而本该是0x5a的位置若是变成了其它内容就意味着多是use-uninitialised问题。更多的poison字节定义参见如下文件:
    /lib/modules/$(uname -r)/build/include/linux/poison.h

(图)SLUB对象的格式
* 绿色的 Payload表示分配出去的 slub object;
* slub debug机制须要占用额外的内存,好比 Red zone,还有,为了追溯 slub object的分配和释放过程,须要额外的空间来存放 stack trace,即图中的 Tracking/Debugging;
* 图中的 FP是 Free Pointer的缩写,处于 free状态的 object是以链表的形式串在一块儿的,FP就是链表指针。bash

怎样开启slub debug

Slub自己包含了完整的debug功能,缺省是关闭的,须要的时候打开就好了。async

开启slub debug有两种方式:ide

  1. 【启动时开启】
    在kernel command line中加入如下参数:
    slub_debug=<Debug-Options>,<slab name>
    它会在重启时生效。
    注:
    slub_debug后面不跟任何参数表示打开全部的debug功能;
    slub_debug=<Debug-Options> 对全部的slab打开指定的debug options;
    slub_debug=<Debug-Options>,<slab name> 对指定的slab打开指定的debug options;
    slub_debug=,<slab name> 对指定的slab打开全部的debug options。
  2. 【运行中开启】
    在运行系统上能够经过如下文件对指定的slab打开指定的debug option:
    /sys/kernel/slab/<slab name>/<debug_file>

Debug options以下:工具

debug option sysfs debug file 功能
F sanity_checks 激活完整性检查功能,在特定的环节好比free的时候增长各类条件判断,验证数据是否无缺。
Z red_zone 用于检测overrun。经过在slub object后面插入一块额外的红色区域(橄榄球术语),一旦进入就表示有错。
P poison 用于检测use-after-free和use-uninitialised。给slub对象填充特征字符,好比在分配时填充0x5a,在释放时填充0x6b,根据特征字符是否被覆盖来检测是否出错。更多的poison字节定义参见: /lib/modules/$(uname -r)/build/include/linux/poison.h
U store_user 在slub object后面添加一块额外的空间,记录调用alloc/free的stack trace
T trace 在slub object alloc/free时,向系统日志中输出相关信息,包括stack trace

开启debug option会下降系统性能,因此尽可能只开启必要的选项。oop

  • 若是slab出现data corruption问题,能够考虑read_zone,poison,store_user,sanity_checks;
  • 若是某个slab的大小持续疯涨,则多是leak(内存泄露),能够开启trace,观察统计slab的alloc/free状况,寻找线索。
    对于内核内存泄漏问题,还有另外一个工具可供选用,详见:用KMEMLEAK检测内核内存泄漏

在kernel commandline中开启slub debug与在运行系统上开启是有区别的。有些debug option不能在运行系统上开启,好比red_zone、store_user须要额外的存储空间来保存debug信息,若是不是从一开始就开启,那么之前分配出去的slub对象就没有debug数据区,会致使对齐问题,并且debug代码也很难分辨新老slub对象;再好比poison,若是不是从一开始就开启,那么之前分配出去的slub对象就没有填充特征字符,debug代码也辨别不了哪些slub对象是有填充的、哪些是没有填充的。因此,在运行系统上开启slub debug,若是指定的slab里面已经有了object,那么只能动态开启sanity_checks和trace,唯有当指定的slab仍是空的,其它的debug option才能够动态开启。咱们实际使用的时候,尽管去试好了,若是某个debug option不容许动态开启,命令就不会成功,好比:gitlab

 

要进行slub debug,有一个重要特性不可不知,那就是slab merging。

Slab merging

不少slab的大小和参数是类似的,slub会把这些不一样的slab合并到一块儿,好处是能够减小内存碎片,提升内存使用效率,这个称为slab merging(合并)。

怎么知道一个slab有没有发生合并呢?经过查看如下文件:
/sys/kernel/slab/<slab name>/aliases
aliases表示参与合并的slab的数量(本身除外),若是大于0就意味着发生了合并。

slabinfo工具(见下一节的介绍)能够具体列出哪些slab合并到了一块儿:

Slab merging会干扰debug,由于不一样的slab合并到了一块儿,出了问题之后很难分辨是哪个slab致使的。关闭slab merging的方法有两个:

  • 在kernel command line中加入“slub_nomerge”;
  • 开启slub debug以后,slab merging就会自动关闭。若是slub_debug指定了某个slab,那么只有指定的slab会关闭merging。
    注:最好是在启动时开启slub_debug,若是是在运行系统上经过sysfs开启slub debug,那么以前已经合并的那些slab仍然会保持合并状态。
slabinfo工具

随内核源程序提供了一个slabinfo工具,可是须要本身手工编译。源程序的位置是在源代码树下的 tools/vm/slabinfo.c,编译方法是:
$ gcc -o slabinfo tools/vm/slabinfo.c
或者进入 tools/vm 目录下直接执行make:
$ make slabinfo

slabinfo工具能作的事情见它的帮助信息:

 

参考资料:

https://www.kernel.org/doc/Documentation/vm/slub.txt
https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-kernel-slab
https://lwn.net/Articles/340267/
https://gitlab.eurecom.fr/oai/odroid-linux-3.10.y-rt/commit/4c13dd3b48fcb6fbe44f241eb11a057ecd1cba75
一个实例分析