内存管理(一)new 和 delete 底层实现

前言

最近在看侯捷老师的内存管理这门课,整理一下课程中的知识和自己的思路。

正文

1.new

在c++的使用中,我们使用new手动申请堆区内存。下面看一下new到底干了什么。
举个例子:
Complex * pc = new Complex(1,2);
这行代码是使用new创建一个Complex型的对象。
在底层编译器实际上是完成下面的事情:

Complex *pc;
try
{ 
void* tmp = operator new(sizeof(Complex)); // 调用operator::new 分配内存
pc = static_cast<Complex*>(tmp); //转换类型
pc->Complex::Complex(1,2); // 调用构造函数(这种形式是编译器实现的形式,只有部分平台可以直接以这种形式调用构造函数)
}
catch(std::bad_alloc)
{
  // 内存分配失败就不执行构造函数
}

所以我们看到了,调用new表达式会执行两个步骤:
1.调用operator::new 分配内存
2.调用构造函数
需要注意的是,如果内存分配失败,会抛出异常,将不会调用构造函数。
那么operator::new 干了什么?

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)                 
{  
    _THROW_NCEE(_XSTD bad_alloc, );
}       
   return (p);       
 }

我们看到,operator::new 实际上是调用了 malloc函数,并且如果malloc失败,会调用callnewh,如果成功,则会再malloc一次,否则抛出异常。
那么callnewh实际上就是调用new_handler(当内存分配失败时的回调函数),我们可以在函数中自己设定功能(比如释放掉一些无关紧要的内存,或结束程序等等)。当进行这些处理后如果还是分配失败,就说明真的没有内存给它分配了,就抛出异常。
可以使用_set_new_handler来设定callnewh所调用的函数。
总结
1.调用operator::new函数申请空间(operator::new 调用 malloc函数),申请失败抛出异常。
2.调用static_cast将空间的类型转换为目标类型。
3.调用构造函数(简单数据类型不需要)。

2.delete

举同一个例子:
delete pc;

pc->~Complex();
operator delete;

先是调用了对象的析构函数,然后调用operator::delete。

void operator delete(void *p)
{
 free(p);
}

由operator::delete调用free来释放内存。

总结:
1.调用对象析构函数(简单数据类型不需要)。
2.调用operator::delete函数(operator::delete 调用 free)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章