查一个内核问题而衍生出更多的关于内核的问题
本帖最后由 chenrvmldd 于 2011-04-21 14:36 编辑
前段时间查一个内核问题大概查了一个星期左右,也在论坛上发了很多帖子求救但是无果,异常痛苦!谨以此文记录查问题的全过程,同时将自己解决问题的思路记录下来,供大家参考!
废话少说,上问题:我linux的版本是2.4.25的,系统跑起来之后:
- / # free
- total used free shared buffers
- Mem: 13956 12316 1640 0 0
- Swap: 0 0 0
- Total: 13956 12316 1640
复制代码通过free命令发现剩余的内存只有:1640k,明显内存不足。刚开始怀疑有可能是缓存内存占用太多:
再次通过:
- # cat /proc/meminfo
- total: used: free: shared: buffers: cached:
- Mem: 14290944 12713984 1576960 0 0 1941504
- Swap: 0 0 0
- MemTotal: 13956 kB
- MemFree: 1540 kB
- MemShared: 0 kB
- Buffers: 0 kB
- Cached: 1896 kB
- SwapCached: 0 kB
- Active: 428 kB
- Inactive: 1716 kB
- HighTotal: 0 kB
- HighFree: 0 kB
- LowTotal: 13956 kB
- LowFree: 1540 kB
- SwapTotal: 0 kB
- SwapFree: 0 kB
复制代码发现并不是由于缓存引起的cache和buffer的值加起来都很小,那么是由于什么问题引起的了?
后来又想到一个命令:/ # ps
- PID Uid VmSize Stat Command
- 1 root 304 S init
- 2 root SW [keventd]
- 3 root SWN [ksoftirqd_CPU0]
- 4 root SW [kswapd]
- 5 root SW [bdflush]
- 6 root SW [kupdated]
- 7 root SW [mtdblockd]
- 8 root SWN [jffs2_gcd_mtd2]
- 16 root 160 S telnetd
- 24 root SWN [jffs2_gcd_mtd3]
- 31 root 236 S vsftpd
- 32 root 456 S /bin/ash
- 36 root 304 R ps
- / #
复制代码统计了一下发现其实应用程序只占用了少量的内存,没有统计出来的都是内核占用的,那么内核占用的为什么统计不出来了?
因为内核共用的是一个mm_struct,这个mm_struct的初始化函数如下:
- #define INIT_MM(name) \
- { \
- mm_rb: RB_ROOT, \
- pgd: swapper_pg_dir, \
- mm_users: ATOMIC_INIT(2), \
- mm_count: ATOMIC_INIT(1), \
- mmap_sem: __RWSEM_INITIALIZER(name.mmap_sem), \
- page_table_lock: SPIN_LOCK_UNLOCKED, \
- mmlist: LIST_HEAD_INIT(name.mmlist), \
- }
复制代码在这个里面根本就没有发现对mm_struct结构体中的:struct vm_area_struct * mmap; /* list of VMAs */这个成员进行初始化
从初始化函数中就可以验证了UTSK书上讲的:struct vm_area_struct * mmap这个结构是面向用户进程的
所以在ps命令中没有关于内核线程占用的虚拟内存的大小。
看来ps命令也没有效果,那么我开始思考:
第一:可以肯定的是内存肯定是被内核占用了!
第二:内核有可能是通过静态的方式占用太多的内存,也就是说定义了太多的静态缓冲区,凭我的直接这种情况应该可能性很小
第三:内核是在初始化的时候通过某种动态的方式不断的申请内存(注意:在我的系统中系统刚起来就占用那么多内存了,我并没有执行任何的应用程序),这个查起来就比较困难了
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
既然得出这三个结论,那么就从第二个结论开始,因为第二个问题验证起来比较方便,看过内核初始化代码的兄弟肯定知道,在初始化的时候有一段如下的代码:
start_kernel->setup_arch函数下面的:
复制代码既然知道了这四个参数,那么,下一步想知道内核静态空间到底占用多大就容易了,有两种方法:
第一种:直接在原有的内核代码上修改内核代码
第二种:自己写一个可动态加载的内核模块
我选择了第二种,其实不管哪一种,都比较容易了,我的代码如下:
复制代码module_init(kernel_size_init);
module_exit(kernel_size_exit);
MODULE_LICENSE("GPL");
[/code]
编译成功之后将,kernel_size这个内核模块加载到内核中去经过测试发现:
(1212k kernel code, 508k data)
从这个参数可以看出内核静态占用的数据段和代码段才1M左右,所以可以肯定的,导致内存被大量占用,一定是内核初始化的时候,动态分配了
很多内存,那么这个问题怎么去查了?
我记得深入理解Linux那本书上曾经介绍过内核的内存的分配比较特殊,主要是通过slab的方式来管理的,那么我想有没有可能是由于内核动态申请了大量的数据结构导致的了?
那么怎么知道内核数据结构占用内存的大小了,可以通过下面的一个命令来查看:
/ # cat /proc/slabinfo
关于slabinfo中参数的含义我就不讲了这个google很容易的
复制代码size-4096这一项引起了我的注意:因为一项占用太多的内存了:总共2055个对象,每个对象占用4096个字节,也就是4K的大小,
大概算一下这一项就占用了8-9M左右的内存。这里建议大家看一下slab.c文件,这个文件对于我们理解slab有非常大的帮助
哈哈,这个时候哥们很激动啊,总算找到原因了,可是突然问题好像又来了,那么这一项到底是谁申请的?为什么会申请这么大了?这个问题貌似更猛!
继续思考:
我们知道对于slab来讲申请内存的话有好几个接口:常用的两个:kmalloc和kmem_cache_alloc,第二个接口一般都是面向具体数据结构的也就是
cat /proc/slabinfo前面列出的那些数据结构,那么size-4096这一项应该是通过kmalloc来分配的,接下来是不是可以通过kmalloc来看了,我大概搜索了一下
在2.4.25的内核中使用kmalloc调用的地方至少有3000个左右,这样的话,我们要一个一个的去看,工作量太大了,而且很不科学,在由于我的linux内核很多功能都是自己公司
添加上去的,那么我想会不会是由于添加的部分导致内核占用内存过多的原因了,后来,我搜索了一下公司增加的若干部分代码有没有kmalloc的调用,经过半天的努力终于
找到了如下的一段代码:
复制代码其中sysctl_host_list_len的定义如下:
int sysctl_hot_list_len = 128*8*2;
从上面的这段代码不难看出:kmalloc被调用了128*8*2=2048 这个值和2055很接近罗。。。。而每次kmalloc都会分配4096个字节,即4K
到这里问题的最终原因总算找到了,好了下面要验证自己的想法了!修改内核参数:
将int sysctl_hot_list_len = 128*8*2;
改为:sysctl_hot_list_len= 128
重新编译内核,将内核文件下载到powepc板子上:
系统起来后:
复制代码发现没有:free的值没有变大了,大概多了8M左右,再看看slabinfo的值:
复制代码注意到没有size-4096这一项的值变为135了。原来是2055,sysctl_hot_list_len = 128*8*2=2048 现在改为128,
2048-128=1920我们少分配了这么多次 2055-1920=135个,正好验证了我的想法
总结一下:
查这个问题总共查了一个多星期,过程总是痛苦的,看了很多资料也阅读了很多代码,以前还觉得网络上的资源很丰富,可是一旦遇到问题的时候发现其实有用的资料少的可怜
通过这个问题主要学到的知识:
第一:slab的具体含义,slab的管理模式
第二:系统对于内存的管理模式
第三:查找内核问题的思路
第四:内核模块的编写