内存模型(堆和栈工作原理,String详解)
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
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。