2009-08-26 92 views
7

Q1。在Java中,所有對象,數組和類變量都存儲在堆中? C++也一樣嗎?數據段是堆的一部分嗎?Stack Frame問題:Java vs C++

以下C++代碼如何?

class MyClass{ 
    private: 
      static int counter; 
      static int number; 
}; 

MyClass::number = 100; 

Q2。就我的理解而言,由編譯器賦予特定值的變量存儲在數據段中,而未經初始化的全局變量和靜態變量存儲在BSS(由符號開始的塊)中。在這種情況下,MyClass :: counter是靜態的,被編譯器初始化爲零,所以它被存儲在BSS中,並且被初始化爲100的MyClass :: number被存儲在數據段中。我的結論是否正確?

Q3。請考慮下面這段代碼:

void doHello(MyClass &localObj){ 
// 3.1 localObj is a reference parameter, where will this get stored in Heap or Stack? 
     // do something 
} 

void doHelloAgain(MyClass localObj){ 
// 3.2 localObj is a parameter, where will this get stored in Heap or Stack? 
     // do something 
} 

int main(){ 
     MyClass *a = new MyClass(); // stored in heap 

     MyClass localObj; 
     // 3.3 Where is this stored in heap or stack? 
     doHello(localObj); 
     doHelloAgain(localObj); 
} 

我希望我已經做了我的問題說清楚所有

編輯:

請BSS

請參閱本 article一些理解

EDIT1 :將類名從MyInstance更改爲MyClass,因爲它名字很差。真誠道歉

EDIT2:改變了類的成員變量數目從非靜態靜態

+0

調用任何時間'new',你mallocing,這意味着無論你用'new'確實保存在堆上創建。我不知道你的意思是「數據段是堆的一部分嗎?」。 – 2009-08-26 18:07:09

+0

MyClass :: number = 100;不會編譯。你是不是指櫃檯? – 2009-08-26 18:32:52

+0

將成員變量編號更改爲靜態 – pankajt 2009-08-26 18:34:27

回答

6

這是有點簡化,但大部分都是我所知的最準確。在Java中,所有對象都分配在堆上(包括所有成員變量)。大多數其他東西(參數)都是引用,並且引用本身與本地類型(int,long等等)一起存儲在堆棧上,但除了與本機類型相比更多的是對象的字符串之外。在C++中,如果要分配所有具有「new」關鍵字的對象,它與java的情況幾乎相同,但在C++中有一個唯一的情況,因爲您可以在堆棧上分配對象(而不是並不總是必須使用「新」)。

另請注意,Java的堆性能比C的堆性能更接近於C的堆性能,垃圾收集器會做一些非常聰明的事情。它還不如堆棧,但比堆堆好得多。這是必須的,因爲Java不能在堆棧上分配對象。

+0

有關java的堆性能和c的堆棧性能比較的很好的信息 – pankajt 2009-08-26 18:27:18

+0

所有Java對象都存儲在堆中,是的。對象變量存儲對它們的引用。原始變量(int,float,bool等)存儲自己的值;他們不是參考。方法參數按值傳遞。 – 2009-08-26 18:31:10

+0

在這一點上,我真的很鄙視整個傳遞的價值/參考術語,並儘量不要使用它。在Java中,最簡單的方法就是記住在處理對象時,你總是有一個引用,你永遠不會傳遞實際的對象。說這不是「通過引用傳遞」混淆了任何人試圖瞭解語言如何工作(即使它是真實的),所以我完全放棄了術語。 – 2009-08-26 21:50:04

2

Q1

爪哇還存儲棧,但類實例上的變量在堆上分配。在C++中,您可以自由地在堆棧或堆上分配您的類實例。通過使用new關鍵字,您可以在堆上分配實例。

數據段不是堆的一部分,但在進程啓動時分配。該堆用於動態內存分配,而數據段是靜態的,並且在編譯時已知內容。

BSS段僅僅是一種優化,其中屬於數據段的所有數據(例如,字符串,常數等)未被初始化或初始化爲零都被移至BSS段。數據段必須嵌入到可執行文件中,並且通過將「全部零」移動到最後,可以將它們從可執行文件中刪除。當加載可執行文件時,BSS段被分配並初始化爲零,編譯器仍然能夠知道BSS段內各種緩衝區,變量等的地址。

Q2

MyClass::number存儲在哪裏MyClass類的實例被分配。它可以在堆上或堆棧中。在Q3中注意a如何指向在堆上分配的MyClass實例,而localObj是在堆棧上分配的。因此a->number位於堆上,而localObj.number位於堆棧上。

由於MyClass::number是一個實例變量,你不能給它分配是這樣的:

MyClass::number = 100; 

但是,你可以指定MyClass::counter,因爲它是靜態的(除了它是私有的):

MyClass::counter = 100; 

Q3

當您撥打doHello變量localObj(在main中)通過引用傳遞。 doHello中的變量localObj指向堆棧上的該變量。如果更改它,更改將被存儲在分配的localObj的堆棧中。

當您撥打doHelloAgain時,變量localObj(在main中)被複制到堆棧上。在doHelloAgain內部,變量localObj被分配在堆棧上並且僅在呼叫期間存在。

+0

問題3:引用(如指針)是32位(通常爲)包含內存地址的值。這在doHello的堆棧中。類「MyInstance」是8個字節(假設int是32位),並且它在doHelloAgain中的堆棧上。 – 2009-08-26 18:26:08

1

Q1。在Java中,所有對象,數組和 類變量都存儲在 堆中? C++也一樣嗎?數據段是否是堆的一部分?

不,數據段與堆是分開的。基本上,數據部分是在加載時分配的,然後在那裏有一個固定的位置。另外,可以在堆棧上分配對象。

對象堆上的唯一時間是如果您使用new關鍵字,或者如果您使用malloc函數系列中的某些東西。第二季度銷售價格指數爲:

Q2。據我瞭解, 由編譯器賦予特定值 的變量存儲在數據段 中,靜態變量存儲在BSS (塊以符號開始)中。在這種情況下 ,MYINSTANCE ::計數器是靜止 是由編譯器 初始化爲零,並且因此它被存儲在BSS和 MYINSTANCE ::數目是 初始化爲100被存儲在 數據段。我正確的做出了 的結論嗎?

是的,您對BSS部分的理解是正確的。然而,由於number也不是一成不變的代碼:

MyInstance::number = 100; 

是不合法的,它需要做出任何靜態或在構造函數正確初始化。如果你在構造函數中初始化它,它將存在於擁有對象被分配的任何地方。如果你把它變成靜態的,它會在數據部分結束......如果有的話。通常可以將static const int變量直接內聯到所使用的代碼中,從而根本不需要全局變量。

Q3。考慮下面的一段代碼:...

void doHello(MyInstance &localObj){

localObj是傳入對象的引用。據你所知,沒有存儲,它指的是傳遞變量的地方。實際上,在引擎蓋下,可以在堆棧上傳遞一個指針以便於實現。但是如果可以的話,編譯器可以輕鬆優化它。

void doHelloAgain(MyInstance localObj){

傳遞的參數的拷貝被放置在堆棧中。

MyInstance localObj; 
// 3.3 Where is this stored in heap or stack? 

localObj在堆棧上。

+0

「對象可以分配在堆棧上」我同意這一點,但是在java的情況下是一樣的嗎? – pankajt 2009-08-26 18:24:24

+3

不,java只分配堆棧中的原語和引用,而不是對象。 – nos 2009-08-26 18:28:32

1

在C++中,對象可以分配在堆棧上...例如,Q3主例程中的localObj。

我感覺到一些關於類與實例的混淆。 「MyInstance」作爲變量名比類名更有意義。在Q1示例中,每個MyInstance類型的對象都有「number」。 「計數器」由所有實例共享。 「MyInstance :: counter = 100」是有效的賦值,但「MyInstance :: number = 100」不是,因爲您尚未指定 哪個對象應將其「數字」成員分配給。

1

在C++中所有內存區域中列出here