内存管理
-
c程序动态地址空间分布
-
无论什么变量,都要和这张图相对应
-
static修饰后,它的生命周期变成全局的了?
- 编译的时候编进了全局数据区
-
验证指针合法性
- 指针如果有具体的指向(包括野指针),对应的合法性我们无法验证,确认指针的正常值的合法性,不是用户能做到的。
- 所有的指针,如果没有被直接使用,必须设置为NULL
- 在函数内部要验证指针的合法性,本质是验证指针!=NULL
- 在内部有一个宏:assert 检测入口指针是否合法,在调试的时候,不是很推荐
- “合法”:能够被用户直接使用!应用层面解决
struct str
{
char* name;
int scope;
};
void showprint(char *str)
{
// 检测入口指针是否合法,在调试的时候
assert(str);
// if (str == NULL)return;
printf("%s", str);
// 合法性
}
int main()
{
struct str zhan = { NULL,0 };
zhan.name = malloc(32);
strcpy(zhan.name, "tom");
showprint(zhan.name);
return 0;
}
- 在开辟空间后,最好是初始化一下
- 空间越界,不一定报错,有可能还是能访问的
- 越界是一个很严重的问题,但是不一定能表现出来
int main()
{
// 开辟空间
int* p = malloc(sizeof(int) * 30);
// 初始化空间
memset(p, 0, sizeof(int) * 30);
for (int i = 0; i < 30; i++)
{
printf("%d \n", p[i]);
}
return 0;
}
- 内存泄漏,只申请不释放
- 如果程序退出了内存泄漏问题还存在吗?
- 内存泄漏:什么样的程序,最怕内存泄漏问题?
- 永远不会主动退出的程序最害怕。
- 操作系统本身,杀毒软件,服务器程序
- 常驻(内存)进程(程序)
- 内存泄漏:什么样的程序,最怕内存泄漏问题?
int main()
{
while (1)
{
int* p = malloc(1024);
}
return 0;
}
free
- 实际malloc申请空间的时候,系统给你的其实更多!
- 多出来的部分:
- 记录这次申请的更详细信息
- 申请了多大的空间
- 申请堆空间,大空间好,还是小空间好?
- 大空间好。
- 栈上申请小空间。
int main()
{
// 释放的字节实际上要比申请的多的多
// 意味着申请一定不止 20 个字节
char* p = (char*)malloc(sizeof(char) * 20);
// 我们目前只知道堆空间的起始地址
// 并没有要传入释放多少字节
free(p);
return 0;
}
- 所谓的free释放,到底在做什么?
- 改变指针,和目标堆空间的对应关系
- 所有的“关系”都是需要数据去维护的。
- 那为什么不能设置为NULL呢?
- 没有必要。你没有权力进行访问,对系统不会造成影响,你非要去访问,需要手动释放。
- 可以在free之后,带上p=NULL;
int main()
{
char* p = (char*)malloc(sizeof(char) * 20);
printf("before %p \n", p);
free(p);
printf("after %p \n", p);
// 前后地址相同 ,但是free后就不能在访问堆空间这个地址了
// 那为什么不能设置为NULL呢?
return 0;
}
- 内存管理的本质是什么?
- 空间什么时候申请,申请多少,什么时候释放,释放多少,释放多少的问题。
- 在c语言中:程序员+场景 = 内存管理