动态内存管理详解
Posted 一朵花花
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态内存管理详解相关的知识,希望对你有一定的参考价值。
申请内存的方式
最简单的申请内存方式:创建变量
(1)局部变量:出了当前代码块就释放内存
(2)全局变量:程序运行结束就释放内存
(3)静态变量:程序运行结束就释放内存
动态内存管理 (即内存的申请和释放 )
目的:
程序运行过程中,更灵活的进行内存的申请和释放~
即:随时需要就申请,随时不要就释放
(一般这样理解)
动态往往是和“运行时”相关~
静态往往是和“编译器”相关~
申请 / 释放操作
由C语言提供的几个库函数完成
1.申请内存:malloc函数
函数原型:
void* malloc (size_t size);
malloc注意事项:
- size表示申请多少个字节的内存
- malloc申请到的是一块连续的内存空间
- 申请到的内存空间并没有指定类型
- 返回值为void*类型,只关注内存大小,不关注大小(大小隐含在参数size里)
- 如果申请成功,则返回申请到内存的起始位置的地址
- 如果申请失败,就会返回一个NULL,在笔试/面试中使用malloc时一定要检查
- malloc申请到的内存,内存会一直存在,直到手动释放(free)或者程序结束为止
代码示例:
int main() {
//malloc申请到的这块空间,可以当成一个“数组”去使用
//其用法类似于数组
int* p = (int*) malloc(4 * sizeof(int));
for (int i = 0; i < 4; i++) {
p[i] = i;
}
for (int i = 0; i < 4; i++) {
printf("%d\\n", p[i]);
}
system("pause");
return 0;
}
2.释放内存:free函数
函数原型:
void free (void* ptr);
功能:释放一个通过动态内存方式申请到的内存空间
free注意事项:
- 若参数 ptr 指向的空间不是动态申请的,会发生未定义行为
- 参数必须传入malloc等动态申请内存函数返回的地址,返回的是什么,就传入什么
- 不能重复释放同一块内存空间
错误代码示例
//错误代码1
int num = 10;
free(&num);
//错误代码2
int* p = (int*)malloc(4 * sizeof(int));
free(p + 1);
//错误代码3
int* p = (int*)malloc(4 * sizeof(int));
free(p);
free(p);
//错误代码4
int* p = (int*)malloc(4 * sizeof(int));
p = (int*)malloc(4 * sizeof(int));
free(p);
等进程结束来释放内存,大概率会发生内存泄漏(memory leak)
内存泄漏的危害:
如果一直持续不断的申请内存而不主动释放,系统中剩余的内存就会越来越少,最终会导致没有内存可以使用,此时程序也会崩溃,若是服务器程序,会更严重
在C语言中,没有太好的方法避免内存泄漏,最稳妥的方法就是不用malloc
C++中,可以使用智能指针,一定程度可以缓解内存泄漏问题
Java / Python / Go / JS等中,通过垃圾回收机制(GC),来解决内存泄露问题
垃圾回收机制,相对于智能指针,能够很大程度的解决内存泄漏问题
3.calloc函数
函数原型:
void* calloc (size_t num, size_t size);
calloc注意事项:
- calloc申请到的内存空间,会自动初始化为全0
- 为num个元素的数组分配一块内存,每个元素是size字节长,并将其所有位初始化为零。
实际开发中并不常用calloc 简单介绍一下即可
4.realloc函数
函数原型:
void* realloc (void* ptr, size_t size);、
功能:针对当前malloc / calloc申请到的内存空间进行扩容
realloc注意事项:
- realloc后的内存空间仍然是连续的内存空间
- ptr是要调整的内存地址
- size是调整之后的内存大小
- realloc得到的地址,最终不用时,也需要通过free来释放
- 故:void * ptr2 = realloc(ptr,size),此处的ptr和ptr2可能相等,也可能不相等
realloc进行扩容的两种情况:
(从10扩容到20为例:)
情况一:原有空间足够大
情况二:原有空间大小不够
realloc两种情况总结:
- 原有的空间有足够大,够容纳下size个字节的内存,直接在原有内存后继续追加即可,原来的空间数据不发生改变
- 原有的空间不够大,要扩容的话,必须在堆上另外找一个连续的内存空间,可以存放size个字节大小,把原来内存的数据拷贝过去,并且释放旧空间
动态内存管理缺点
动态内存管理太过灵活,故太容易出错
但C语言中没有其他方案,故还是需广泛使用动态内存管理~
后面会发一些常见的错误代码~~
以上是关于动态内存管理详解的主要内容,如果未能解决你的问题,请参考以下文章