! https://zhuanlan.zhihu.com/p/145953980

这章好硬盒啊,暂时有点啃不动,先写一点

为什么free()不知道内存长度就能准确释放内存?

其实就是问内存管理器,我明明没告诉你内存长度,你怎么能删除得这么准确呢?
老生常谈。从gdb调试的例子开始

  1. 1 #include <stdio.h>
  2. 2 #include <stdlib.h>
  3. 3
  4. 4 int main()
  5. 5 {
  6. 6 char * p1 = (char *)malloc(16);
  7. 7 char * p2 = (char *)malloc(16);
  8. 8 for(int i = 0; i < 16; i++)
  9. 9 {
  10. 10 p1[i] = (i + 1);
  11. 11 p2[i] = (i + 1);
  12. 12 }
  13. 13
  14. 14 printf("P1: %p, P2: %p\n", p1, p2);
  15. 15 free(p1);
  16. 16 free(p2);
  17. 18 return 0;
  18. 19 }

编译,GDB调试

  1. Breakpoint 1, main () at memdemo.cpp:14
  2. 14 printf("P1: %p, P2: %p\n", p1, p2);
  3. (gdb) p p1
  4. $1 = 0x602010 "\001\002\003\004\005\006\a\b\t\n\v\f\r\016\017\020"
  5. (gdb) p p2
  6. $2 = 0x602030 "\001\002\003\004\005\006\a\b\t\n\v\f\r\016\017\020"
  7. (gdb) x/16x 0x602000
  8. 0x602000: 0x00000000 0x00000000 0x00000021 0x00000000
  9. 0x602010: 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d
  10. 0x602020: 0x00000000 0x00000000 0x00000021 0x00000000
  11. 0x602030: 0x04030201 0x08070605 0x0c0b0a09 0x100f0e0d

可以看到,先是打印了p1,p2的内存地址,然后列出了从0x602000开始的地址。
很多人觉得奇怪,连续分配的内存,但是却没有紧挨在一起,中间都隔了16字节的内存,而且内容完全一样。
这是内存中的隐藏头技术,实际内存总要比你分配的大,一部分用来存储元信息。malloc好像是地址往前8字节划分为元信息,但是这个例子中却划分了16字节,可能这个是malloc分配的最小单位。

是注意倒着看, 0x00000000 0x00000021,这个就是内存的元信息。因为是内存以16字节为单位划分大小,所以最低四位没有意义(一次内存分配不可能小于16),也就是有意义的只有 0x2 也就是 32, 代表说实际一共分配了32字节,free的时候free这么多就行了。

其他待写

  • brk和mmap
  • 内存重释放,栈溢出,内存泄漏