8.1.2 堆内存的释放
堆是由程序员来管理的一块内存区域,它的大小并非是无限的,如果不断地进行申请分配,总有将堆内存空间耗费殆尽的时刻。就像一个停车场,如果只有车停进来,而没有车开出去,则该停车场迟早会因所有的停车位被占满而无法继续提供服务。因此,当堆中的对象或数据不再使用时,要及时将其所占用的内存释放回收,就像车被开走,而让停车场重新获得空的停车位一样。
C 语言中,释放堆内存的函数为 free,它的原型为:
void free( void* ptr );
free 函数没有返回值,参数 ptr 是一个 void 类型的指针。函数功能为释放参数 ptr 所指向的一段堆内存空间。可以将 malloc 或 calloc 函数所返回的指针作为实参进行 free 函数的调用。例如:
int *p = (int*)malloc(sizeof(int)); free(p);
首先通过 malloc 函数在堆中申请分配 int 类型大小的一段内存空间,并将返回值初始化给 int 类型指针变量 p。然后调用 free 函数,将指针 p 作为实参,即表示将指针 p 所指向的堆内存释放,即将之前通过 malloc 函数所申请分配的内存释放回收。
在调用 free 函数之后,参数指针所指向的堆内存就会被释放回收。因此,不应该再通过指针来访问或修改内存区域的数据。例如:
int *p = (int*)malloc(sizeof(int)); free(p); //释放指针 p 指向的堆内存 *p = 100; //修改指针 p 所指向的内存数据
在调用 free 函数后,指针 p 所指向的堆内存已经被释放,可以认为此时的指针 p 指向了一片未知的内存区域,通常将这种指向未知内存区域的指针,称为野指针或者迷途指针。如果对野指针进行解引用,从而访问和修改内存数据,就会产生不确定行为,导致程序出现错误结果或者引发异常,并且这种错误调试起来也相对困难,因此应予以杜绝。最好的办法就是,在释放堆内存后及时地将指针设置为空指针。例如:
int *p = (int*)malloc(sizeof(int)); free(p); //释放指针 p 指向的堆内存 p = NULL; //将指针 p 设置为空指针 *p = 100; //修改指针 p 所指向的内存数据
在释放堆内存后,将指针 p 的值赋为 NULL,即指针 p 成为空指针。后面再对指针 p 进行解引用并修改其值为 100 时,就会引发程序运行时错误。
另外,在进行堆内存释放的时候,还有两点需要注意:
1.释放要准确
释放的只能是堆内存,也就是调用 free 函数时,参数应该是一个指向堆内存的指针,不要对其他内存空间进行释放操作。例如:
int a = 100; int *p = &a; free(p);
指针 p 指向的是变量 a,而变量 a 是存储在栈中的,栈中内存的申请分配和释放都是由系统自动管理的,因此,不要使用 free 来释放栈中的内存。
2.释放要及时
当堆中对象或数据不再使用时,要及时释放,防止内存泄漏现象发生。所谓内存泄漏,堆中内存被占用而无法被释放。例如:
int *p = (int*)malloc(sizeof(int)); p = NULL; free(p);
第一条语句通过 malloc 函数在堆中申请分配了 int 类型大小的内存,并将返回值初始化给指针变量 p,即指针 p 指向了在堆中所申请分配的内存。第二条语句将指针 p 重新赋值为 NULL,即将指针 p 设置为空指针。此时,没有任何指针指向在堆中所申请分配的内存,因此,这块堆内存就会一直被占用而无法被释放回收,导致内存泄漏现象发生。第三条语句虽然将指针 p 作为参数来调用 free 函数,但由于此时的指针 p 是一个空指针,因此,是不会释放回收任何内存的。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论