2011-09-10 52 views
1

我不知道如何適當的就是這個問題,但 -內存分配(C++)編譯時間/運行時間?

我好奇的編譯器是如何爲它的構造,甚至之前(甚至構造函數被調用之前的對象(內存分配),可將內存一邊去! )

它是如何發生的基本數據類型?

這聽起來有點幼稚,但它究竟是什麼?

它是完全運行時間過程,或者它(編譯)有像任何計劃要做到這一點,在運行時,它在編譯期在手之前決定時間。我根本不知道!

對象,無論是原始類型,指針還是大類的實例都佔用一定量的已知內存。這種記憶必須以某種方式留給對象。在某些情況下,該預留存儲器被初始化。初始化是構造函數的作用。它們不會留出(或分配)存儲對象所需的內存。該步驟在調用構造函數之前執行。

換句話說,什麼時候從字面上ANY類型的變量的內存分配發生,在時間上,在哪一點?編譯(或運行時)的哪個步驟?

回答

5

內存分配總是在運行時發生。對於駐留在堆棧中的對象或靜態變量,內存預留髮生在編譯時(或在C99 VLA的運行時)。

內存爲對象的成員總是在地方構造運行之前。確保編譯器及其運行時支持的工作就是如此。

+0

靜態變量可能會在可執行文件本身中被賦予空間(然後被內存映射到進程的地址空間中),所以它們在編譯時被完全分配。 :) – jalf

+0

謝謝大衛...... :)但是這導致了一個小問題。 **內存分配**和**內存預留**!從你所說的話,我明白兩者之間是有區別的。你能解釋給我嗎? :) – jsp99

+0

@jalf我忘記了這一點。我已將靜態變量添加到我稱爲保留的類別,而不是分配。 –

2

使用newnew[]或某些變體創建的分配對象在運行時完成,方法是在構造函數運行之前訪問freestore並找到足夠空間放置新對象。

函數內的本地對象的分配在運行時完成。然而,這通常通過將堆棧指針移動到正確的字節大小來實現,並且現在爲對象保留之前值和新值之間的空間。構造函數在空間運行後運行。

對全局和靜態對象

分配是在編譯時由編譯器完成,它們的構造函數,當他們在加載定義的轉換單元(通常在main()開始執行)運行。另一個目的內

分配用於直接包含的對象(未通過指針)作爲分配給該對象的一部分來完成。

+1

我會說,本地對象的大部分分配是在編譯時完成的,因爲編譯器發出的機器代碼期望對象相對於當前的堆棧幀處於特定偏移量,並且此偏移量在編譯時決定時間。 –

2

有(嚴格意義上)三種典型的方案:在棧上分配,從堆分配和靜態分配。

首先是當你在函數內聲明的局部變量會發生什麼:

void foo () 
{ 
    int bar = 42; 
} 

這裏,bar內存是在stack分配。它被調用時分配foo

void foo () 
{ 
    MyClass* bar = new MyClass(); 
} 

這裏,i內存是在heap分配:

第二種情況,當你創建一個new操作一個類的實例發生。這又發生在運行時,並且在new運算符執行時發生。如果你對此更熟悉,它的工作原理與C的malloc相同。

最後,有靜態分配。

void foo () 
{ 
    static int bar = 42; 
} 

這裏,編譯器知道提前時間內存將需要bar,所以它插入到可執行告訴可執行文件加載器來預留空間的指令,或從字面上使得空間在可執行的因此bar的內存通常仍在運行時分配,因爲可執行程序會加載。

+1

我懷疑靜態分配「字面上」佔用可執行映像中的空間。設想一個全局'char buf [1000000];'你的可執行文件不會增長1MB,而是在*加載時間內將內存留出。 –