内核中accept连接时创建socket结构错误导致的内存泄露

本文讲述了作者在内核模块开发中遇到的因调用sock_create()而非sock_alloc()在accept时导致的内存泄露问题。通过分析进程、slab和pagetable的内存消耗,最终发现TCP slab缓存增长异常,进而定位到错误的socket结构创建方式。总结了排查问题的经验教训,强调了正确理解和使用内核API的重要性。
摘要由CSDN通过智能技术生成
  强烈推荐一下淘宝褚霸的这篇文章: http://blog.yufeng.info/archives/2456
  注:这里我们只关心TCP套接字,所以文章中说sock结构或者socket结构的时候都只针对TCP协议。
 
  在测试内核模块时,内核会因为内存耗尽而panic,使用crash工具查看core文件,提示的信息是"Kernel panic - not syncing: Out of memory and no killable processes..."。也就是说内核没有内存可以使用,并且也没有进程可以杀死来释放内存。不用说,肯定是发生了内存泄露!写这篇文章是为了总结一下查找这个BUG的过程,反思一下。在这个过程中用到了很多工具和方法,写下来对遇到类似问题的人或许有些帮助。
  内核中运行的程序主要是我的内核模块和应用层的HTTP服务器。所以造成内核泄露要么是内核模块,要么是HTTP服务器。
  问题出在HTTP服务器的可能性不大,首先这个服务器已经上线了挺长时间,相对比较稳定;其次如果是应用进程占用的内存过多,内核完全会杀死这个用户进程来释放内存,也就不会出现“Out of memory and no killable processes”这样的信息。所以基本可以肯定问题出在内核模块上。为了保险,还是要看一下应用层的服务器进程占用了多少内存。其中一台服务器的内存比较小,所以在这个机器上问题很快就可以重现。在内存消耗量比较大(通过free -m可以看到)时,通过top命令查看应用服务器进程占用的RSS内存(也可以通过/proc/[pid]/statem文件查看),应用服务器占用的内存只有100多M。接着查看进程占用的文件数,也就是连接数,这个信息可以通过/proc/[pid]/fd目录获取。应用服务器占用的连接数也非常少。通过查看应用服务器实际占用的内存数和连接数,现在就要开始去内核模块中查找问题了。

  我的内核模块在sysfs中注册了相应的项,通过这些可以看到当前占用的内存数量。这些项的统计信息都是在分配内存成功、释放之后更新的,可以实时反映当前的内存占用信息。为了方便,我编写了一个脚本,每隔一秒就把这些信息刷到终端上,如下图所示:


  total_mem项的单位是KB,所以这里看到占用的内存大约为3M。内存统计的地方都已经反复地检查过了,所以这个量是可信的。这个结果不是我想看到的,如果统计出来的量大的话,我就会从内核模块分配和释放的地方去找问题。但是现在这个量这么小,很明显不是内核模块中调用kmalloc()或kmem_cache_alloc()(内核模块调用)分配的内存没有被释放。这个时候很容易陷入迷茫,估计很多人都会去反复地检查自己的代码,看看是否有内存没有释放的地方。如果我最开始也这样做的话,或许也能早点发现BUG,但是也有可能要花更长的时间。一般情况下,代码中有很多不同功能的模块,每个模块的功能复杂度不同。你去检查代码往往会忽略功能简单的模块,即使是在遇到BUG的时候。而且这样盲目地去遍历各个可能出问题的地方,也很不明智,因为你现在了解到的信息还太少。所以,这个时候,首先要做的不是去检查代码,而是首先要先通过各种工具和手段,来看一看内存究竟用到了什么地方。你现在遇到的问题,很多前辈们也遇到过。为了方便快捷地解决遇到的问题,前辈们已经为我们开发出了很多很多方便好用的工具,为什么不拿来用呢?貌似扯的有点远了,继续我们的问题.......
  很庆幸看到了霸爷的《Linux Used内存到底哪里去了?》这篇文章,所在我决定先按照这篇文章的方法,找到系统被使用的内存都在哪里。正如文章中所说的,内存主要用3个去向:进程消耗、slab消耗和pagetable消耗。其中pagetable消耗是内核管理页面时的消耗,也就是struct page等结构的消耗。slab消耗不仅包括管理slab结构本身的消耗,还包括每个slab缓存

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值