前言
前面提到了 malloc 虚拟内存分配相关的内容
malloc 虚拟内存分配的调试(1)
malloc 虚拟内存分配的调试(2)
这里提 calloc 和 realloc, 这两个函数 虽然没有 malloc 使用频率那么高
但是 还是有很大的知名度的, 本文这里 我们来看一下
calloc
此函数传入两个参数, 第一个参数是需要申请的 空间的数量, 第二个参数是 需要申请的空间的单位长度, 会申请 num 个大小为 size 的空间
calloc 的处理就是申请 申请 num 个大小为 size 的空间, 然后将这部分空间 每一个字节 初始化为 0
测试用例如下
root@ubuntu:~/ClionWorkStations/HelloWorld# cat Test01Sum.c
#include "stdio.h"
int main(int argc, char** argv) {
int x = 2;
int y = 3;
int z = x + y;
char *p1 = (char *)malloc(20);
char *p2 = (char *)malloc(20);
*p1 = '1';
*(p1+1) = '2';
free(p2);
void *p3 = calloc(2, 20);
printf("p1 : 0x%x - 0x%x \n", p1, p2);
printf("p3 : 0x%x - 0x%x \n", p3, p3);
}
先看一下 main 中的代码信息, 可以确定 我们断点是在 calloc(2, 20) 的地方
传入的 num 为 2, elem_size 为 20
这里计算出 总共占用的空间为 2 * 20 = 40 字节
申请 40 字节的空间, 地址为 0x602050
前面的 p1, p2 对应的 chunk 分别为 0x602000, 0x602020, 并且占用空间分别为 0x20 字节, top 中下一个空闲空间为 0x602040, 因此 这里用户拿到 mem/p3 是 0x602050
接下来就是 将分配的空间 置为0 的操作了
这里的优化很细节
realloc
realloc 如果更新之后的空间更小了
如果拆分剩余的空间小于 32,则保留原样
否则 将当前 chunk 拆分成两个 chunk
如果更新以后的空间更大
则 如果当前是 top 最近的一块空间,尝试从 top 直接扩展,
如果 下一个 chunk 有足够的空间,合并两个 chunk 然后再拆分需要的空间,
否则 尝试分配空间
如果分配空间为下一个 chunk 则合并当前 chunk
复制原来的 chunk 的数据到 新的 chunk 的数据,然后 free 原来的 chunk
测试用例如下
root@ubuntu:~/ClionWorkStations/HelloWorld# cat Test01Sum.c
#include "stdio.h"
int main(int argc, char** argv) {
int x = 2;
int y = 3;
int z = x + y;
char *p1 = (char *)malloc(20);
char *p2 = (char *)malloc(20);
*p1 = '1';
*(p1+1) = '2';
free(p2);
void *p3 = realloc(p1, 10);
printf("p1 : 0x%x - 0x%x \n", p1, p2);
printf("p3 : 0x%x - 0x%x \n", p3, p3);
}
这是 realloc 更新之后空间 更小的情况
1. 如果拆分之剩余的 chunk 小于 MINSIZE[32字节], 则当前 chunk 原封不动的返回
2. 将当前 chunk 拆分成两个 chunk, 前面部分为保留的 chunk 返回, 后面部分的 chunk 更新 malloc 头, 然后 free 回收到空闲链表
这里的输出如下
p1 : 0x602010 - 0x602030
p3 : 0x602010 - 0x602010
更新 realloc 指定空间为 30, 这是 realloc 更新之后空间 更大的情况
这里 realloc 的是 p1, p1 对应的 chunk 为 0x602000 大小为 0x20 字节, 因此 next 为 0x602020, 对应的是 p2
top 对应的是 0x602040
如果下一个 chunk 为 top, 并且空间足够, 则在当前 chunk 的基础上直接扩展 top, 并更新调整之后的 剩余的 chunk 的 malloc 头
如果下一个 chunk 空闲, 并且空间足够, 则 merge 当前 chunk 和下一个 chunk, 然后尝试进行 chunk 的拆分[流程和上面 realloc 空间更小的情况一致]
否则 则尝试重新分配需要的空间 - 见下一张截图
尝试重新分配需要的空间
如果分配到了下一个 chunk, 则和上面一样, merge 当前 chunk 和下一个 chunk, 然后尝试进行 chunk 的拆分[流程和上面 realloc 空间更小的情况一致]
否则就是 将原有空间的数据拷贝到 重新分配的空间, 然后之后 回收掉原来的空间
realloc(p1, 40) 就是这里的情况, 其他的情况可以自行测试
p1 : 0x602010 - 0x602030
p3 : 0x602050 - 0x602050
因为空间的分配都依赖的是 malloc 的实现, 忽略掉 malloc 的实现之后
这里的 空间分配简单得多了, 但是要理解更细节的东西, 还得理解 malloc 的分配规则
完