【发布时间】:2012-05-19 10:18:37
【问题描述】:
我有一个带有 Linux 2.6 内核的 Debian,我试图了解堆在 malloc() 和 free() 下的工作/行为方式。我试图搜索malloc() 和free() 算法和堆结构,但找不到任何有用的东西。不幸的是,我对 Linux 和内存的工作原理知之甚少,无法理解 free() 和 malloc() 的源代码。
这是一个示例代码:
int main(int argc, char **argv)
{
char *a, *b, *c;
a = malloc(32);
b = malloc(32);
c = malloc(32);
strcpy(a, argv[1]);
strcpy(b, argv[2]);
strcpy(c, argv[3]);
free(c);
free(b);
free(a);
}
使用gdb 和run AAAA BBBB CCCC 我可以检查堆。这是strcpys 之后但frees 之前的状态:
(gdb) x/32x 0x804c000
0x804c000: 0x00000000 0x00000029 0x41414141 0x00000000
0x804c010: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c020: 0x00000000 0x00000000 0x00000000 0x00000029
0x804c030: 0x42424242 0x00000000 0x00000000 0x00000000
0x804c040: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c050: 0x00000000 0x00000029 0x43434343 0x00000000
0x804c060: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c070: 0x00000000 0x00000000 0x00000000 0x00000f89
您可以很好地看到 char 数组。然后我试图弄清楚为什么会有 0x29(12 月 41 日)。我希望像 0x20(12 月 32 日)或 0x24(12 月 36 日)这样的东西。
- 为什么 malloc 算法会浪费这个空间?
- 怎么判断是0x29?
- 最后的 0xf89 代表什么?
- 程序如何跟踪分配的内容和空闲的内容?
特别想了解free() 的工作原理。三个释放后,堆看起来像这样:
(gdb) x/32x 0x804c000
0x804c000: 0x00000000 0x00000029 0x0804c028 0x00000000
0x804c010: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c020: 0x00000000 0x00000000 0x00000000 0x00000029
0x804c030: 0x0804c050 0x00000000 0x00000000 0x00000000
0x804c040: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c050: 0x00000000 0x00000029 0x00000000 0x00000000
0x804c060: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c070: 0x00000000 0x00000000 0x00000000 0x00000f89
- 为什么用这个特定的地址替换 char 数组?
- free 的伪代码是什么?
看这个例子:
(gdb) run AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDDDD BBBB CCCC
...
(gdb) x/32x 0x804c000
0x804c000: 0x00000000 0x00000029 0x41414141 0x41414141
0x804c010: 0x41414141 0x41414141 0x41414141 0x41414141
0x804c020: 0x41414141 0x41414141 0x44444444 0x00000044
0x804c030: 0x42424242 0x00000000 0x00000000 0x00000000
0x804c040: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c050: 0x00000000 0x00000029 0x43434343 0x00000000
0x804c060: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c070: 0x00000000 0x00000000 0x00000000 0x00000f89
...
(gdb) c
Program exited with code 021.
我已经覆盖了 0x29,但程序正常退出。 但是当我添加另一个字节时,我遇到了分段错误:
(gdb) run AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADDDDD BBBB CCCC
...
(gdb) x/32x 0x804c000
0x804c000: 0x00000000 0x00000029 0x41414141 0x41414141
0x804c010: 0x41414141 0x41414141 0x41414141 0x41414141
0x804c020: 0x41414141 0x41414141 0x44444444 0x00004444
0x804c030: 0x42424242 0x00000000 0x00000000 0x00000000
0x804c040: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c050: 0x00000000 0x00000029 0x43434343 0x00000000
0x804c060: 0x00000000 0x00000000 0x00000000 0x00000000
0x804c070: 0x00000000 0x00000000 0x00000000 0x00000f89
...
(gdb) c
Program received signal SIGSEGV, Segmentation fault.
0x080498b9 in free (mem=0x804c030) at common/malloc.c:3631
对我来说最重要的问题是:
- 为什么当您覆盖更多字节时,
free()中会出现分段错误? -
free()算法是如何工作的? - malloc 和 free 如何跟踪地址?
非常感谢您的阅读, 亲切的问候
【问题讨论】:
-
你看过Doug Lea's malloc吗?
-
我认为标准的 glibc malloc 实现称为ptmalloc。
-
这是我在 SO 上看到的最好的问题之一。
标签: c linux memory-management gdb heap-memory