我在 https://blog.youkuaiyun.com/wowricky/article/details/83218126 介绍了一种内存池,它的实现类似于linux 中打开slub_debug (1. make menuconfig: Kenel hacking -> Memory Debugging, 2. comand line中传入slub_debug=PZU) 时slub 对象池。
首先我们先看一下slub_debug没有打开时的 slub obj 所占memory layout,预期如下:
为了查看slub obj 内存布局,我写了一个kernle module, code上传至github: https://github.com/greenricky/slub_debug 摘抄主要的代码片段如下:
void print_mem_detail(char *addr, int head_size, int buf_size,int foot_size)
{
if(NULL==addr || head_size<0 || buf_size<0 || foot_size<0)
return;
printk("---Ahead %d bytes---\n", head_size);
print_layout(addr-head_size, head_size);
printk("---Buf %d bytes---\n", buf_size);
print_layout(addr, buf_size);
printk("---Footer %d bytes---\n", foot_size);
print_layout(addr+buf_size, foot_size);
}
static int __init my_test_init(void)
{
printk("greenricky: init\n");
buf = kmalloc(mem_size, GFP_KERNEL);
printk("===============kmalloc=================\n");
print_mem_detail(buf, head_size, mem_size, foot_size);
memset(buf, 0x57, mem_size);
printk("\n===============memset buf to 0x57======\n");
print_mem_detail(buf, head_size, mem_size, foot_size);
kfree(buf);
printk("\n===============free buf====================\n");
print_mem_detail(buf, head_size, mem_size, foot_size);
return 0;
}
思路如下:
- 申请n个bytes大小的内存,
- 打印刚刚分配出的内存布局;(obj 前head_size个 bytes + obj + obj 后foot_size个 bytes);
- 打印memset obj 后的内存布局;
- 打印free obj 后的内存布局;
在下例中我们实际申请48个bytes的内存,通过查看内核给我们分配是kmalloc-64 obj. 下图是刚刚kmalloc后的内存布局,还没有用memset进行赋值。
# insmod slub.ko head_size=64 mem_size=48 foot_size=64
===============kmalloc=================
---Ahead 64 bytes---
ee598300: 05 47 c2 ee 14 ec c0 ee 14 ec c0 ee c4 1d 03 c0
ee598310: 00 00 00 00 70 58 7b c0 00 a0 eb ee 0c a0 eb ee
ee598320: 00 00 00 00 00 00 00 00 00 00 00 00 4c 52 23 c0
ee598330: 00 a0 eb ee 00 00 00 00 00 00 00 00 00 00 00 00
---Buf 48 bytes---
ee598340: 80 83 59 ee 65 73 74 5f 69 6e 69 74 20 5b 73 6c
ee598350: 75 62 5d 00 00 00 00 00 00 00 00 00 00 00 00 00
ee598360: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
---Footer 64 bytes---
ee598370: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
ee598380: c0 83 59 ee 00 00 00 00 00 00 00 00 00 00 00 00
ee598390: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
ee5983a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
通过上述打印出来的内存布局来看,我们申请的内存起始地址0xee598340, 结束地址是0xee59837f, 长度为64bytes.
请关注一点,内存区域起始地址的前4个bytes是FP- free pointer, 也就是指向下一个可用object 地址,这里是0xee598380, 而0xee598380正好是我们申请到的内存区域的结束地址的后一个byte。我们继续观察0xee598380 开始这段内存,起始的4个bytes是0xee5983c0, 也就是下一个可用object的地址。
为了更好的理解上述内存布局,截图注释如下:
本例中object size为48 bytes (前4个bytes存储的是FP), obj align 长度为16bytes。
本章介绍的是slub_debug 关闭情况下的内存布局,下一章我们介绍slub_debug 打开情况下的内存布局,好戏才刚刚开始。