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