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