內存管理(一)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)。

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