存放j**a在函式中定義的基本型別的變數的引用和資料,以及物件的引用都放在棧中儲存。
主要存放new出來的物件和陣列。
儲存已經被虛擬機器載入的類資訊、常量、靜態變數,即編譯器編譯後的**等資料。
靜態變數、常量在方法區;所有方法,包括靜態和非靜態的,也在方法區。
靜態常量池
靜態常量池存在於class檔案中。
執行時常量池
執行時常量池,就是在class檔案被載入進了記憶體之後,常量池儲存在了方法區中,通常說的常量池值的是執行時常量池。所以呢,討論的都是執行時常量池。
字串常量池
string a = "abc";
string b = new string("abc");
system.out.println(a==b);
結果:false
物件b儲存在堆中,這個是不用質疑的,
而a作為字面量一開始儲存在了class檔案中,之後執行期,轉存至方法區中。
它們兩個就不是同乙個地方儲存的。
例項string s1 = "hello";
string s2 = "hello";
string s3 = "hel" + "lo";
string s4 = "hel" + new string("lo");
string s5 = new string("hello");
string s6 = s5.intern();
string s7 = "h";
string s8 = "ello";
string s9 = s7 + s8;
system.out.println(s1 == s2); // true; s1 和 s2 都指向了方法區常量池中的hello。
system.out.println(s1 == s3); // true; 因為做+號的時候,會進行優化,自動生成hello賦值給s3,所以也是true
system.out.println(s1 == s4); // false; s4是分別用了常量池中的字串和存放物件的堆中的字串,做+的時候會進行動態呼叫,最後生成的仍然是乙個string物件存放在堆中。
system.out.println(s1 == s9); // false; 在j**a9中,因為用的是動態呼叫,所以返回的是乙個新的string物件。所以s9和s4,s5這三者都不是指向同一塊記憶體
system.out.println(s1 == s6); // true; 歸功於intern方法,這個方法首先在常量池中查詢是否存在乙份equal相等的字串如果有的話就返回該字串的引用,沒有的話就將它加入到字串常量池中,所以存在於class中的常量池並非固定不變的,可以用intern方法加入新的.
public class test
}// 我們可以發現,
// 對於final型別的常量它們已經在編譯中被確定下來,
// 自動執行了+號,把它們拼接了起來,所以就相當於執行了"123" + "456";
public class test2
public static void main(string args)
}// 上個例子是在編譯期間,
// 就已經確定了a和b,但是在這段**中,
// 編譯期static不執行的,a和b的值是未知的,
// static**塊,在初始化的時候被執行,初始化屬於類載入的一部分,
// 屬於執行期。看看反編譯的結果,很明顯使用的是indy指令,
// 動態呼叫返回string型別物件。
// 乙個在堆中乙個在方法區常量池中,自然是不一樣的。
c 棧區 堆區 常量區
c 中棧區 堆區 常量區 由一道面試題目而學習 2009 04 28 21 01 include void main 對應的彙編 10 a c 1 00401067 8a 4d f1 mov cl,byte ptr ebp 0fh 0040106a 88 4d fc mov byte ptr ebp...
C 中棧區 堆區 常量區
c 中棧區 堆區 常量區 由一道面試題目而學習 2009 04 28 21 01 include void main 對應的彙編 10 a c 1 00401067 8a 4d f1 mov cl,byte ptr ebp 0fh 0040106a 88 4d fc mov byte ptr ebp...
堆區 棧區 靜態區 常量區還有???
常見的儲存區域可分為 由編譯器在需要的時候分配,在不需要的時候自動清楚的變數的儲存區。裡面的變數通常是區域性變數 函式引數等。由new分配的記憶體塊,他們的釋放編譯器不去管,由我們的應用程式去控制,一般乙個new就要對應乙個delete。如果程式設計師沒有釋放掉,程式會一直占用記憶體,導致記憶體洩漏...