標籤:ati 通過 arch java.net 連結 nbsp 存在 資源 程式
在講述這些之前我們需要一些預備知識:
java中的記憶體被分成以下部分:
1、棧區:由編譯器自動分配釋放,具體方法執行結束後,系統自動釋放JVM記憶體資源。
其作用有儲存局部變數的值,包括:1.用來儲存基礎資料型別 (Elementary Data Type)的值;2.儲存類的執行個體,即堆區對象的引用(指標)。也可以用來儲存載入方法時的幀。
2、堆區:一般由程式員分配釋放,JVM不定時查看這個對象,如果沒有引用指向這個對象就回收。
其作用為用來存放動態產生的資料,比如new出來的對象。注意建立出來的對象只包含屬於各自的成員變數,並不包括成員方法。
因為同一個類的對象擁有各自的成員變數,儲存在各自的堆中,但是他們共用該類的方法,並不是每建立一個對象就把成員方法複製一次。
3、代碼區:存放程式中方法的二進位代碼,而且是多個對象共用一個代碼空間地區。
4、資料區:用來存放static定義的靜態成員。
5、常量池:JVM為每個已載入的類型維護一個常量池,常量池就是這個類型用到的常量的一個有序集合。包括直接常量(基本類型,String)和對其他類型、方法、欄位的符號引用。池中的資料和數組一樣通過索引訪問。由於常量池包含了一個類型所有的對其他類型、方法、欄位的符號引用,所以常量池在Java的動態連結中起了核心作用。常量池存在於堆中。
大致描述了JAVA的記憶體配置
接來下我們來看一段代碼執行個體:
1 public class TestStringConstant { 2 public static void main(String args[]) { 3 // 字串常量,分配在Data Segment,編譯器會對其進行最佳化, 4 // 即當一個字串已經存在時,不再重複建立一個相同的對象,而是直接將s2也指向"hello". 5 String s1 = "hello"; 6 String s2 = "hello"; 7 // new出來的對象,分配在heap中.s3與s4雖然它們指向的字串內容是相同的,但是是兩個不同的對象. 8 // 因此==進行比較時,其所存的引用是不同的,故不會相等 9 String s3 = new String("world"); 10 String s4 = new String("world");11 12 System.out.println(s1 == s2); // true13 System.out.println(s3 == s4); // false14 System.out.println(s3.equals(s4)); // true 15 // String中equals方法已經被重寫過,比較的是內容是否相等.16 }17 }
通過以上相信大家對於字串常量的分配地區以及java的記憶體配置有了一個較為形象的瞭解。
下面是一些相關知識點的補充與注意事項:
1.分清什麼是執行個體什麼是對象。Class a= new Class();此時a叫執行個體,而不能說a是對象。執行個體在棧中,對象在堆中,操作執行個體實際上是通過執行個體的指標間接操作對象。多個執行個體可以指向同一個對象。
2.棧中的資料和堆中的資料銷毀並不是同步的。方法一旦結束,棧中的局部變數立即銷毀,但是堆中對象不一定銷毀。因為可能有其他變數也指向了這個對象,直到棧中沒有變數指向堆中的對象時,它才銷毀,而且還不是馬上銷毀,要等記憶體回收掃描時才可以被銷毀。
3.以上的棧、堆、程式碼片段、資料區段等等都是相對於應用程式而言的。每一個應用程式都對應唯一的一個JVM執行個體,每一個JVM執行個體都有自己的記憶體地區,互不影響。並且這些記憶體地區是所有線程共用的。這裡提到的棧和堆都是整體上的概念,這些堆棧還可以細分。
4.類的成員變數在不同對象中各不相同,都有自己的儲存空間(成員變數在堆中的對象中)。而類的方法卻是該類的所有對象共用的,只有一套,對象使用方法的時候方法才被壓入棧,方法不使用則不佔用記憶體。
注:以上僅僅談及了stack與heap這兩個部分,但是還有一個較為麻煩的部分——常量池。本文這裡對此不再敘述,想要瞭解的可移步以下內容:
http://www.blogjava.net/Jack2007/archive/2008/05/21/202018.html
http://developer.51cto.com/art/201009/225071_1.htm
淺談JAVA中字串常量的儲存位置