1 C/C++内存分布
栈区:由编译器自动分配和释放,存放运行时候的局部变量,函数参数,返回数据,返回地址。
堆区:一般由程序员自己分配,然后自己释放,例如栈的实现malloc开辟的数组空间。
数据段(静态区):存放全局变量,静态数据,常量,程序结束后自动释放。
代码段(常量区):存放常量字符串和可执行代码,程序结束自动释放。
2 C语言中动态内存管理方式:malloc/calloc/realloc/free
malloc:开辟空间,不初始化 (int*)malloc(sizeof(int)):开辟一个int大小的空间。
calloc:开辟空间并把每个字节初始化为0。(int*)calloc(4,sizeof(int)):开辟4个int大小的空间。
realloc(用于扩容):在内存找一段连续大小的空间,将传入的指针指向的内存内的字节全部拷贝过来,然后释放原指针空间,再把新大小的空间指针返回。(int*)realloc(_ptr,sizeof(int)*10)。
free:释放一段连续空间。free(_ptr),释放完之和_ptr为野指针,一般需要_ptr=NULL。
3 C++内存管理实现
C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。
在对内置类型开辟空间时new和malloc实质上是没什么区别的,但在对自定义类对象进行空间开辟时候,new和malloc的区别在于malloc只负责开辟空间不会进行初始化,而new开辟空间的同时会调用自定义类内的构造函数进行初始化。
注意:申请和释放单个元素的空间,使用new和delete操作符,申请和释放连续的空间,使用new[]和delete[],注意:匹配起来使用。
new/delete和malloc/free最大的区别在于,new/delete开辟空间会调用构造函数,结束会调用析构函数。而malloc/free不会。
operator new与operator delete
new和delete是用户进行动态内存申请和释放的操作符,operator new 和operator delete是系统提供的全局函数,new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。
/*
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间失败,
尝试执行空
间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。
*/
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
// try to allocate size bytes
void *p;
while ((p = malloc(size)) == 0)
if (_callnewh(size) == 0)
{
// report no memory
// 如果申请内存失败了,这里会抛出bad_alloc 类型异常
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return (p);
}
/*
operator delete: 该函数最终是通过free来释放空间的
*/
void operator delete(void *pUserData)
{
_CrtMemBlockHeader * pHead;
RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
if (pUserData == NULL)
return;
_mlock(_HEAP_LOCK); /* block other threads */
__TRY
/* get a pointer to memory block header */
pHead = pHdr(pUserData);
/* verify block type */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
_free_dbg( pUserData, pHead->nBlockUse );
__FINALLY
_munlock(_HEAP_LOCK); /* release other threads */
__END_TRY_FINALLY
return;
}
/*
free的实现
*/
#define free(p) _free_dbg(p, _NORMAL_BLOCK)
通过上述两个全局函数的实现知道,operator new 实际也是通过malloc来申请空间,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete 最终是通过free来释放空间的。
说白了operator new就是new子过程,new就等价于operator new之和在调用构造函数。而operator new在程序设计上又是由malloc为基础,区别于malloc的就是malloc申请空间失败之和返回值是0。而operator new申请空间失败后是直接抛异常。
定位new表达式
定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如果是自定义类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化。
我们用malloc为p3开辟一个结构体大小的空间后,成员变量并没有初始化,但由于成员变量为private修饰的在外不可访问,这时候就可以利用定位new去进行初始化。
定位new格式为new(变量)+类名(初始化)。
malloc/free与new/delete的区别
共同点是都在堆上申请空间,需要用户手动释放。
区别是malloc/free是函数而new/delete是操作符。
malloc/free使用时候只开辟空间和销毁空间,而new/delete开辟空间会调用构造函数初始化,销毁空间会调用析构函数。
malloc返回值是void*使用时候需要强转类型,而new不用,编译器自动识别。
malloc申请空间失败返回的是NULL,而new申请空间失败会抛异常。
内存泄露
什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。
内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死。