用户态内存泄漏好查,有Valgrind、ASan这些神器。但内核态?那完全是另一回事。
内核模块一旦泄漏内存,不会像用户进程那样被OOM Killer干掉,而是一直占着内存,直到系统重启才能释放,更麻烦的是内核没有独立的地址空间隔离,一个驱动的泄漏可能把整个系统拖垮。
那Linux内核是怎么检测内存泄漏的?
答案是kmemleak。这玩意儿是Linux内核内置的内存泄漏检测器,从2.6.31版本开始引入,原理类似用户态的垃圾回收器,但它不会真的回收内存,只是把"疑似泄漏"的内存块报告出来,让你自己去查。
这篇文章会深入kmemleak的源码,把检测原理讲透。读完之后,你会理解三件事:内核是怎么追踪每一次内存分配的?扫描算法怎么工作?为什么有些泄漏它检测不出来?
不过在讲kmemleak之前,得先搞清楚Linux内核的内存管理机制。否则后面的内容会看不懂。
一、Linux内核内存管理:从页到slab
用户态程序调用malloc分配内存,最终会通过brk或mmap系统调用向内核申请。内核态代码分配内存则用的是另一套API:kmalloc、kzalloc、vmalloc、kmem_cache_alloc,这些名字你可能都见过。
这些API的底层,是Linux内核的多层内存管理架构。理解这个架构,才能理解kmemleak是怎么工作的。
1.1 物理页:内存管理的基本单位
Linux内核管理内存的基本单位是页(Page),通常是4KB。所有物理内存被划分成一个个页框(Page Frame),内核用str