JVM主要管理兩種類型內存:堆和非堆。
1.堆是運行時數據區域,所有類實例和數組的內存均從此處分配,這些對象通過new、newarray、 anewarray和multianewarray等指令建立。堆由垃圾收集器來回收內存,它的優勢是可以動態分配內存大小,缺點就是存取較慢。
2.非堆就是堆之外的內存,它包括:
1)方法區
2)JVM內部處理或優化所需的內存(如 JITCompiler,Just-in-time Compiler,即時編譯後的代碼緩存)
3)類結構(如運行時常數池、字段和方法數據)
4)方法和構造方法的代碼
3.棧的優勢是,存取速度比堆要快,僅次於寄存器,棧數據可以共享。但缺點是,存在棧中的數據大小與生存期必須是確定的,缺乏靈活性。棧中主要存放一些基本類型的變量數據(int, short, long, byte, float, double, boolean, char)和對象句柄(引用)。
String常量
1.一個String常量,它的值在常量池中(jvm爲每個被裝載的類型維護的一個有序集合)
2.常量池在內存中是以表的形式存在的,它用一個固定長度的字段來CONSTANT_String_info來存儲字符串的值(不存儲符號引用)。
3.所以當程序執行的時候,Method area中的常量池保存了很多String對象,它們可以被共享使用,不用每次在創建時都在堆中重新分配一塊內存,所能夠提高效率。
1)賦值
String s1 = "abc"; //↑ 在字符串池創建了一個對象 String s2 = "abc"; //↑ 字符串pool已經存在對象“abc”(共享),所以創建0個對象,累計創建一個對象 System.out.println("s1 == s2 : "+(s1==s2)); //↑ true 指向同一個對象, System.out.println("s1.equals(s2) : " + (s1.equals(s2)));2)new String(),通過new 創建的String對象會在堆中開闢兩塊內存
String s3 = new String("abc"); //↑ 創建了兩個對象,一個存放在字符串池中,一個存在與堆區中; //↑ 還有一個對象引用s3存放在棧中 String s4 = new String("abc"); //↑ 字符串池中已經存在“abc”對象,所以只在堆中創建了一個對象 System.out.println("s3 == s4 : "+(s3==s4)); //↑false s3和s4棧區的地址不同,指向堆區的不同地址; System.out.println("s3.equals(s4) : "+(s3.equals(s4))); //↑true s3和s4的值相同 System.out.println("s1 == s3 : "+(s1==s3)); //↑false 存放的地區多不同,一個棧區,一個堆區 System.out.println("s1.equals(s3) : "+(s1.equals(s3))); //↑true 值相同3)字符串拼接,兩個字符串拼接,會產生新的對象
String str6 = "b"; String str7 = "a" + str6; String str67 = "ab"; System.out.println("str7 == str67 : "+ (str7 == str67)); //false ↑str6爲變量,在運行期纔會被解析。 final String str8 = "b"; String str9 = "a" + str8; String str89 = "ab"; System.out.println("str9 == str89 : "+ (str9 == str89)); //true ↑str8爲常量變量,編譯期會被優化
4)String.intern()
String的 intern()方法就是擴充常量池的 一個方法;當一個String實例str調用intern()方法時,Java 查找常量池中 是
否有相同Unicode的字符串常量,如果有,則返回其的引用,如果沒有,則在常 量池中增加一個Unicode等於str的字
符串並返回它的引用。
String s0 = "你好";
String s1 = new String("你好");
String s2 = new String("你好");
s1.intern(); //雖然執行了s1.intern(),但它的返回值沒有賦給s1,所以s1沒變
s2 = s2.intern(); //把常量池中"你好"的引用賦給s2
System.out.println( s0 == s1); //flase
System.out.println( s0 == s1.intern() ); //true//說明s1.intern()返回的是常量池中"你好"的引用
System.out.println( s0 == s2 ); //true