linux内核内存泄露检测

linux内核内存泄露检测,第1张

经常碰到系统跑着跑着一段时间内存满了,出现内存泄漏的问题,系统软件太庞大,这类问题又不好直接从源码中分析,所以需要借助工具来分析了,kmemleak就是这样的一个工具。

在Kernel hacking中打开CONFIG_DEBUG_KMEMLEAK =y即使能了kmemleak,其实就是开了一个内核线程,该内核线程每10分钟(默认值)扫描内存,并打印发现新的未引用的对象的数量。kmemleak的原理其实就是通过kmalloc、vmalloc、kmem_cache_alloc等内存的分配,跟踪其指针,连同其他的分配大小和堆栈跟踪信息,存储在PRIO搜索树。如果存在相应的释放函数调用跟踪和指针,就会从kmemleak数据结构中移除。下面我们看看具体的用法。

查看内核打印信息详细过程如下:

1、挂载debugfs文件系统

   mount -t debugfs nodev /sys/kernel/debug/

2、开启内核自动检测线程

   echo scan > /sys/kernel/debug/kmemleak

3、查看打印信息

   cat /sys/kernel/debug/kmemleak

4、清除内核检测报告,新的内存泄露报告将重新写入/sys/kernel/debug/kmemleak

   echo clear > /sys/kernel/debug/kmemleak

内存扫描参数可以进行修改通过向/sys/kernel/debug/kmemleak 文件写入。 参数使用如下:

  off 禁用kmemleak(不可逆)

  stack=on 启用任务堆栈扫描(default)

  stack=off 禁用任务堆栈扫描

  scan=on 启动自动记忆扫描线程(default)

  scan=off 停止自动记忆扫描线程

  scan=<secs>设置n秒内自动记忆扫描,默认600s

  scan 开启内核扫描

  clear 清除内存泄露报告

  dump=<addr>转存信息对象在<addr>

通过“kmemleak = off”,也可以在启动时禁用Kmemleak在内核命令行。在初始化kmemleak之前,内存的分配或释放这些动作被存储在一个前期日志缓冲区。这个缓冲区的大小通过配CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE设置。

是不是说没有一种内存检查工具能够在linux使用呢,也不是,像valgrind工具还是相当不错的。他的下载地址是 下载一个valgrind 3.2.3 (tar.bz2) 工具,按照里面的README提示,安装后就可以使用这个工具来检测内存泄露和内存越界等。这是一个没有界面的内存检测工具,安装后,输入valgrind ls -l 验证一下该工具是否工作正常(这是README里面的方法,实际上是验证一下对ls -l命令的内存检测),如果你看到一堆的信息说明你的工具可以使用了。 在编译你的程序时,请设置-g参数,编译出后使用如下的命令来判断你的程序存在内存泄露: valgrind --tools=memcheck --leak-check=full yourProg在输出信息中就会看到你的内存问题了。

出现内存泄漏的主机为集群机器,运行时间约5天,内存使用超90%,其上运行 集群管理软件 和 docker并执行测试脚本反复启停容器。

长时间运行后,集群主机内存占用逐渐增加,出现应用 OOM 现象。

而实际查看时发现主机内存总占用高,但应用实际占用内存低或未见显著异常。

可以看到内存占用 83.6% ,而实际top显示的内存占用最高也才 0.6% 没有占用内存过高的应用。

内存占用除了用户应用占用还有内核占用,遂查看内核内存占用。

使用linux文件系统接口查看

可以看到占用超高的项目为 slab 内核占用:

继续查看内核详细占用,按照缓存大小进行排序

可以看到此处:

kmalloc-2048,kmalloc-4096,kernfs_node_cache,kmalloc-1024,kmalloc-192,kmalloc-512 均占用较高,对比了正常主机,已经严重超过正常值。

如果是内核缓存过高则可以尝试进行内核缓存释放:

但执行上述 *** 作后,内存占用依旧无显著下降,也符合上面看到的 SUnreclaim: 2447108 kB //slab 不可回收内存大小 。这部分内存不能被释放。

kmalloc 为内核进行分配的内存,参考价值较大的为 kernfs_node_cache 占用高,遂搜索该项是作何作用。

很明显,该现象为内核占用严重超标,于是在搜索时加入了 memory leak 关键字,很快发现了该 Issues docker-run --memory slab cache leak on centos7

该 issue 表示 centos7 在反复运行 docker run --rm --memory 1g hello-world 时存在明显的内核内存占用升高,且无法被释放。且现象和当前现象一致。

最终指向内kernel c group内存泄露问题 slab leak causing a crash when using kmem control group

大致原因是在 3.10 内核上如果使用了 kmem limit 参数,会导致cgroup回收时无法释放部分已分配内存。至于更深入的了解,还需要其他时间,先解决目前的问题。

原因大概确定,为了再次确定这个问题,如果能够通过上述手段复则可以确定是该问题。

在一台仅运行docker的机器上执行上述语句,查看 slab 内存占用,可以看见内存占用明显上升。且最终表现和已有环境上的问题一致,总内存占用高,用户态内存占用低,内核内存占用高且无法被释放。

既然是内核问题,且知道了明确复现路径,则可以通过两种方式进行解决:

最终,进过测试后,选择了更换内核版本,将使用 Ubuntu 18.04 作为新的 *** 作系统。

Linux内核使用层次化内存管理的方法,每一层解决不同的问题,从下至上的关键部分如下:

slab是Linux *** 作系统的一种内存分配机制。其工作是针对一些经常分配并释放的对象,如进程描述符等,这些对象的大小一般比较小,如果直接采用伙伴系统来进行分配和释放,不仅会造成大量的内碎片,而且处理速度也太慢。而slab分配器是基于对象进行管理的,相同类型的对象归为一类(如进程描述符就是一类),每当要申请这样一个对象,slab分配器就从一个slab列表中分配一个这样大小的单元出去,而当要释放时,将其重新保存在该列表中,而不是直接返回给伙伴系统,从而避免这些内碎片。slab分配器并不丢弃已分配的对象,而是释放并把它们保存在内存中。当以后又要请求新的对象时,就可以从内存直接获取而不用重复初始化。

Slab导致的占用内存过高,Slab可以对可回收缓存手动释放, *** 作如下:

其中drop_caches的4个值有如下含义:


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/8346832.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-04-15
下一篇 2023-04-15

发表评论

登录后才能评论

评论列表(0条)

保存