C和C++中动态内存管理与内存泄漏剖析

c语言

c语言中使用malloc/calloc/realloc/free函数进行动态内存管理,malloc/calloc/realloc用来在堆上开辟空间,free将申请的空间释放掉!
malloc:从内存池中提取一个合适的内存,并向该程序返回一个指向这块内存的指针。但是这块内存并没有以任何方式进行初始化。需要手动对它进行初始化或者使用calloc(下面我们会说到)函数。当一块以前分配的内存不再使用时,程序调用free函数把它归还给内存池。
这两个函数的原型如下所示,他们都在头文件stdio.h中声明。

void *malloc(size_t size);
void free(void *pointer);

我们看到malloc的参数就是需要分配的内存字节(字符)数。(注意参数类型是size_t定义与stdlib.h,是一个无符号类型)如果内存池中的可用内存可以满足这个需求,malloc就返回一个指向被分配的内存块起始位置的指针。
无符号类型:
unsigned char // 无符号字符型 ,能表示的数的范围为0~(2^8-1)
unsigned int // 无符号整型 ,能表示的数的范围为0~(2^16-1)
unsigned long int // 无符号长型 ,能表示的数的范围为0~(2^16-1)
堆中实例:

void Funtest()
{
int *p=(int*)malloc(10*sizeof(int));
Dosomething();
if(p!=NULL)
{
free(p);
p = NULL;
}
}

注意:
1:malloc分配的是一个连续的内存
2:如果操作系统无法向malloc提供更多的内存,malloc就会返回一个NULL指针,因此要判断从malloc返回的指针是否为空。
calloc:也用于分配内存,区别于malloc是在返回指向内存的指针之前把它初始化为0。
函数原型为:

void *calloc(size_t num_elements,
             size_t element_size);

calloc的参数包括所需元素的数量和每个元素的字节数。
实例;

int *p1=(int*)calloc(10,sizeof(int));
Dosomething();
if(p1!=NULL)
{
free(p1);
p1=NULL;
}

calloc将申请的内存空间初始化为0。
realloc:用于修改一个原先已经分配的内存块的大小,使用此函数可以是一块内存扩大或者缩小。如果他用于扩大一个内存块,那么这个内存块原先的内容依然保留把新增加的内存添加到原先内存块的后面,新内存块并未以任何方法进行初始化。如果它用于缩小一个内存块,该内存块结尾的部分内存便被拿掉,生育部分内存的原先内容依然被保留。
原型:

void realloc(void *ptr,size_t new_size);

实例:

int *p3 = (int*)malloc(10*sizeof(int));
realloc(p3,100*sizeof(int));
Dosomething();
free(p3);

注意:
1:如果原先的内存块无法改变大小,realloc将分配另一块正确大小的内存,并把原先那块内存的内容复制到新的块上,返回新的指针。
2:如果realloc的第一个参数是NULL,它的行为就可malloc一样。
c语言中常见的内存泄漏:

void MemoryLeaks()
{
//1:内存申请了忘记释放
int *p = int(int*)malloc(10*sizeof(int));
Dosomething();
assert(NULL!=p);
//2:程序逻辑不清,以为释放了
int *p=
int(int*)malloc(10*sizeof(int));
int *p1=
int(int*)malloc(10*sizeof(int));
Dosomething();
p=p2;
free(p);
free(p1);
//吧p2的地址赋值给p了,那么释放p就不是malloc返回的那块空间了,造成内存泄漏
//3:程序误操作,将堆破坏
char *p2 = (char*)malloc(5);
strcpy(p2,"Memory Leaks!");
free(p2);
//4:释放时传入的地址和申请时的地方不相同
int *p3 =(int*)malloc(10*sizeof(int));
assert(NULL!=p3);
p3[0] = 0;
p3++;
Dosomething();
free(p4); 

最常见的错误就是忘记检查所请求的内存是否分配成功,下面用一个技巧可以很可靠的进行这个错误检查(不易发生错误的内存分配器):

//定义一个不易发生错误的内存分配器//alloc.h
#include <stdlib.h>
#include <stdio.h>
#define malloc    //直接调用因为语法错误无法编译
#define MALLOC(num,type) (type*)alloc((num)*sizeof(type));
extern void *alloc(size_t size);
//实现//alloc.c
#include <stdio.h>
#include "alloc.h"
#undef malloc
 void *alloc(size_t size)
 {
 void *new_mem;
 new_mem = malloc(size);
 if(new_mem == NULL)
 {
 printf("out of memory!\n");
 exit(1);
 }
 return new_mem;
 }
 //实现内存分配//client.c
 #include "alloc.h"
 void function()
 {
 int *new_memory;
 new_memory = MALLOC(25,int);
 }

c++

c++中通过new和delete运算符进行内存管理。
在缺省情况下空闲存贮区中的类对象的分配和释放由在C++标准库中定义的全局操
作符new()和delete()来执行。如果一个类提供了两个分别被称为操作符new()和操作符delete()的成员函数那么它就可以承接自己的内存管理权。如果在类中定义了这些成员操作符则它们会被调用以取代全局操作符来分配和释放该类型的对象。
这里写图片描述
这里写图片描述
由上图我们看到new用来分配空间,delete用来释放空间。
new和delete,new[]和delete[]一定要匹配 ,否则可能出现内存泄漏甚至崩溃的问题。
【new作用】
调用operator new分配空间。
调用构造函数初始化对象。
【delete作用】
调用析构函数清理对象
调用operator delete释放空间
【new[]作用】
调用operator new分配空间。
调用N次构造函数分别初始化每个对象。
【delete[]作用】
调用N次析构函数清理对象。
调用operator delete释放空间。
【malloc/free和new/delete的区别和联系】
1. 它们都是动态管理内存的入口。
2. malloc/free是C/C++标准库的函数,new/delete是C++操作符。
3. malloc/free只是动态分配内存空间/释放空间。而new/delete除了分配空间还会调用构造函数和
析构函数进行初始化与清理(清理成员)。
4. malloc/free需要手动计算类型大小且返回值会void*,new/delete可自己计算类型的大小,返回对应类型的指针
总结:
1. operator new/operator delete operator new[]/operator delete[] 和 malloc/free用法一
样。
2. 他们只负责分配空间/释放空间,不会调用对象构造函数/析构函数来初始化/清理对象。
3. 实际operator new和operator delete只是malloc和free的一层封装。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值