C++new和delete实现原理(汇编解释)
new和delete最終調(diào)用malloc和free,關(guān)于malloc和free實(shí)現(xiàn)原理參見(jiàn)這篇文章:
http://blog.csdn.net/passion_wu128/article/details/38964045
new
new操作針對(duì)數(shù)據(jù)類型的處理,分為兩種情況:
1,簡(jiǎn)單數(shù)據(jù)類型(包括基本數(shù)據(jù)類型和不需要構(gòu)造函數(shù)的類型)
代碼實(shí)例:
int* p = new int;
匯編碼如下:
?? ?int* p = new int;
00E54C44 ?push ? ? ? ?4 ?
00E54C46 ?call ? ? ? ?operator new (0E51384h) ?
00E54C4B ?add ? ? ? ? esp,4 ?
分析:傳入4byte的參數(shù)后調(diào)用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)
? ? ? ? ? ? ? ? { ? ? ? // report no memory
? ? ? ? ? ? ? ? ? ? ? ? _THROW_NCEE(_XSTD bad_alloc, );
? ? ? ? ? ? ? ? }
?
? ? ? ? return (p);
? ? ? ? }
分析:調(diào)用malloc失敗后會(huì)調(diào)用_callnewh。如果_callnewh返回0則拋出bac_alloc異常,返回非零則繼續(xù)分配內(nèi)存。
這個(gè)_callnewh是什么呢?它是一個(gè)new handler,通俗來(lái)講就是new失敗的時(shí)候調(diào)用的回調(diào)函數(shù)。可以通過(guò)_set_new_handler來(lái)設(shè)置。下面舉個(gè)實(shí)例:
#include <stdio.h>
#include <new.h>
int MyNewHandler(size_t size)
{
?? ?printf("Allocation failed.Try again");
?? ?return 1;?? ??? ?//continue to allocate
?? ?//return 0;?? ??? ?//stop allocating,throw bad_alloc
}
void main()
{
?? ?// Set the failure handler for new to be MyNewHandler.
?? ?_set_new_handler(MyNewHandler);
?
?? ?while (1)
?? ?{
?? ??? ?int* p = new int[10000000];
?? ?}
}
在new基本數(shù)據(jù)類型的時(shí)候還可以指定初始化值,比如:
int* p = new int(4);
總結(jié):
簡(jiǎn)單類型直接調(diào)用operator new分配內(nèi)存;
可以通過(guò)new_handler來(lái)處理new失敗的情況;
new分配失敗的時(shí)候不像malloc那樣返回NULL,它直接拋出異常。要判斷是否分配成功應(yīng)該用異常捕獲的機(jī)制;
2,復(fù)雜數(shù)據(jù)類型(需要由構(gòu)造函數(shù)初始化對(duì)象)
代碼實(shí)例:
class Object
{
public:
?? ?Object()
?? ?{
?? ??? ?_val = 1;
?? ?}
?
?? ?~Object()
?? ?{
?? ?}
private:
?? ?int _val;
};
?
void main()
{
?? ?Object* p = new Object();
}
匯編碼如下:
?? ?Object* p = new Object();
00AD7EDD ?push ? ? ? ?4 ?
00AD7EDF ?call ? ? ? ?operator new (0AD1384h) ?
00AD7EE4 ?add ? ? ? ? esp,4 ?
00AD7EE7 ?mov ? ? ? ? dword ptr [ebp-0E0h],eax ?
00AD7EED ?mov ? ? ? ? dword ptr [ebp-4],0 ?
00AD7EF4 ?cmp ? ? ? ? dword ptr [ebp-0E0h],0 ?
00AD7EFB ?je ? ? ? ? ?main+70h (0AD7F10h) ?
00AD7EFD ?mov ? ? ? ? ecx,dword ptr [ebp-0E0h] ?
00AD7F03 ?call ? ? ? ?Object::Object (0AD1433h) ? ? ? ?//在new的地址上調(diào)用構(gòu)造函數(shù)
00AD7F08 ?mov ? ? ? ? dword ptr [ebp-0F4h],eax ?
00AD7F0E ?jmp ? ? ? ? main+7Ah (0AD7F1Ah) ?
00AD7F10 ?mov ? ? ? ? dword ptr [ebp-0F4h],0 ?
00AD7F1A ?mov ? ? ? ? eax,dword ptr [ebp-0F4h] ?
00AD7F20 ?mov ? ? ? ? dword ptr [ebp-0ECh],eax ?
00AD7F26 ?mov ? ? ? ? dword ptr [ebp-4],0FFFFFFFFh ?
00AD7F2D ?mov ? ? ? ? ecx,dword ptr [ebp-0ECh] ?
00AD7F33 ?mov ? ? ? ? dword ptr [p],ecx ?
總結(jié):
new 復(fù)雜數(shù)據(jù)類型的時(shí)候先調(diào)用operator new,然后在分配的內(nèi)存上調(diào)用構(gòu)造函數(shù)。
delete
delete也分為兩種情況:
1,簡(jiǎn)單數(shù)據(jù)類型(包括基本數(shù)據(jù)類型和不需要析構(gòu)函數(shù)的類型)。
int *p = new int(1);
delete p;
delete的匯編碼如下:
?? ?delete p;
00275314 ?mov ? ? ? ? eax,dword ptr [p] ?
00275317 ?mov ? ? ? ? dword ptr [ebp-0D4h],eax ?
0027531D ?mov ? ? ? ? ecx,dword ptr [ebp-0D4h] ?
00275323 ?push ? ? ? ?ecx ?
00275324 ?call ? ? ? ?operator delete (0271127h)?
分析:傳入?yún)?shù)p之后調(diào)用operator delete,其源碼如下:
void operator delete( void * p )
{
? ? RTCCALLBACK(_RTC_Free_hook, (p, 0));
?
? ? free( p );
}
RTCCALLBACK默認(rèn)是空的宏定義,所以這個(gè)函數(shù)默認(rèn)情況下就是簡(jiǎn)單的調(diào)用free函數(shù)。
總結(jié):
delete簡(jiǎn)單數(shù)據(jù)類型默認(rèn)只是調(diào)用free函數(shù)。
2,復(fù)雜數(shù)據(jù)類型(需要由析構(gòu)函數(shù)銷毀對(duì)象)
代碼實(shí)例:
class Object
{
public:
?? ?Object()
?? ?{
?? ??? ?_val = 1;
?? ?}
?
?? ?~Object()
?? ?{
?? ??? ?cout << "destroy object" << endl;
?? ?}
private:
?? ?int _val;
};
?
void main()
{
?? ?Object* p = new Object;
?? ?delete p;
}
部分匯編碼如下:
012241F0 ?mov ? ? ? ? dword ptr [this],ecx ?
012241F3 ?mov ? ? ? ? ecx,dword ptr [this] ?
012241F6 ?call ? ? ? ?Object::~Object (0122111Dh) ? ? ? ? ? ? ? ? ? ? ? ? ?//先調(diào)用析構(gòu)函數(shù)
012241FB ?mov ? ? ? ? eax,dword ptr [ebp+8] ?
012241FE ?and ? ? ? ? eax,1 ?
01224201 ?je ? ? ? ? ?Object::`scalar deleting destructor'+3Fh (0122420Fh) ?
01224203 ?mov ? ? ? ? eax,dword ptr [this] ?
01224206 ?push ? ? ? ?eax ?
01224207 ?call ? ? ? ?operator delete (01221145h) ?
0122420C ?add ? ? ? ? esp,4?
總結(jié):
delete復(fù)雜數(shù)據(jù)類型先調(diào)用析構(gòu)函數(shù)再調(diào)用operator delete。
new數(shù)組
new[]也分為兩種情況:
1,簡(jiǎn)單數(shù)據(jù)類型(包括基本數(shù)據(jù)類型和不需要析構(gòu)函數(shù)的類型)。
new[] 調(diào)用的是operator new[],計(jì)算出數(shù)組總大小之后調(diào)用operator new。
值得一提的是,可以通過(guò)()初始化數(shù)組為零值,實(shí)例:
char* p = new char[32]();
等同于:
char *p = new char[32];
memset(p, 32, 0);
總結(jié):
針對(duì)簡(jiǎn)單類型,new[]計(jì)算好大小后調(diào)用operator new。
2,復(fù)雜數(shù)據(jù)類型(需要由析構(gòu)函數(shù)銷毀對(duì)象)
實(shí)例:
class Object
{
public:
?? ?Object()
?? ?{
?? ??? ?_val = 1;
?? ?}
?
?? ?~Object()
?? ?{
?? ??? ?cout << "destroy object" << endl;
?? ?}
private:
?? ?int _val;
};
?
void main()
{
?? ?Object* p = new Object[3];
}
new[]先調(diào)用operator new[]分配內(nèi)存,然后在p的前四個(gè)字節(jié)寫(xiě)入數(shù)組大小,最后調(diào)用三次構(gòu)造函數(shù)。
實(shí)際分配的內(nèi)存塊如下:
這里為什么要寫(xiě)入數(shù)組大小呢?因?yàn)閷?duì)象析構(gòu)時(shí)不得不用這個(gè)值,舉個(gè)例子:
class Object
{
public:
?? ?Object()
?? ?{
?? ??? ?_val = 1;
?? ?}
?
?? ?virtual ~Object()
?? ?{
?? ??? ?cout << "destroy Object" << endl;
?? ?}
private:
?? ?int _val;
};
?
class MyObject : public Object
{
public:
?? ?~MyObject()
?? ?{
?? ??? ?cout << "destroy MyObject" << endl;
?? ?}
private:
?? ?int _foo;
};
?
void main()
{
?? ?Object* p = new MyObject[3];
?? ?delete[] p;
}
釋放內(nèi)存之前會(huì)調(diào)用每個(gè)對(duì)象的析構(gòu)函數(shù)。但是編譯器并不知道p實(shí)際所指對(duì)象的大小。如果沒(méi)有儲(chǔ)存數(shù)組大小,編譯器如何知道該把p所指的內(nèi)存分為幾次來(lái)調(diào)用析構(gòu)函數(shù)呢?
總結(jié):
針對(duì)復(fù)雜類型,new[]會(huì)額外存儲(chǔ)數(shù)組大小。
delete數(shù)組
delete[]也分為兩種情況:
1,簡(jiǎn)單數(shù)據(jù)類型(包括基本數(shù)據(jù)類型和不需要析構(gòu)函數(shù)的類型)。
delete和delete[]效果一樣
比如下面的代碼:
int* pint = new int[32];
delete pint;
?
char* pch = new char[32];
delete pch;
運(yùn)行后不會(huì)有什么問(wèn)題,內(nèi)存也能完成的被釋放。看下匯編碼就知道operator delete[]就是簡(jiǎn)單的調(diào)用operator delete。
總結(jié):
針對(duì)簡(jiǎn)單類型,delete和delete[]等同。
2,復(fù)雜數(shù)據(jù)類型(需要由析構(gòu)函數(shù)銷毀對(duì)象)
釋放內(nèi)存之前會(huì)先調(diào)用每個(gè)對(duì)象的析構(gòu)函數(shù)。
new[]分配的內(nèi)存只能由delete[]釋放。如果由delete釋放會(huì)崩潰,為什么會(huì)崩潰呢?
假設(shè)指針p指向new[]分配的內(nèi)存。因?yàn)橐?字節(jié)存儲(chǔ)數(shù)組大小,實(shí)際分配的內(nèi)存地址為[p-4],系統(tǒng)記錄的也是這個(gè)地址。delete[]實(shí)際釋放的就是p-4指向的內(nèi)存。而delete會(huì)直接釋放p指向的內(nèi)存,這個(gè)內(nèi)存根本沒(méi)有被系統(tǒng)記錄,所以會(huì)崩潰。
總結(jié):
針對(duì)復(fù)雜類型,new[]出來(lái)的內(nèi)存只能由delete[]釋放。
原文:https://blog.csdn.net/passion_wu128/article/details/38966581?
?
總結(jié)
以上是生活随笔為你收集整理的C++new和delete实现原理(汇编解释)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 漏桶算法与令牌桶算法
- 下一篇: c++中创建类型测试