Java 内存分配:举例分析堆栈常量池


String s = new String(“string”),产生了几个对象?引发的思考

直接举栗子,一个一个分析:

第一个


  	// 引用变量str1和str2在栈中,而helloworld在常量池中
  	String str1 = "hellowporld";
    String str2 = "hellowporld";
    System.out.println(str1 == str2); // true
   

分析
首先字符串是一个特殊的包装类,它的引用变量(str1)存在栈里,而它对象的内容(helloworld)则根据创建方式不同存放在常量池或者堆中:在编译期已经创建好的字符串,放在字符串常量池中;在运行时被创建的,就是使用new关键字创建的,则存放在堆里

这里属于第一种情况,创建一个字符串,这时在常量池中查找是否已经存在“helloworld”字符串,此时不存在,则在常量池中创建“helloworld”字符串,并将引用变量str1的地址指向常量池中的“helloworld”。然后创建第二个字符串时,在常量池中查找发现已经存在“helloworld”字符串(常量池中只允许存在一个helloworld),这时就把str2的地址也指向常量池中存在的的“helloworld”,那么str1和str2存的是同一个helloworld的地址,所以为输出true。

---------努力的分割线

第二个

	
	// 引用变量str3和str4在栈中,且指向的是在堆中new创建的helloworld(常量池中也会有这个对象)
	String str3 = new String("helletwo"); // 这里创建了两个对象
    String str4 = new String("helletwo"); // 这里创建了一个对象
    String str5 = "helletwo";

    System.out.println(str3 == str4); // false
    System.out.println(str3 == str5); // false

    str3 = str3.intern(); // 调用intern方法使str3指向常量池中“hellotwo”的地址
    System.out.println(str3 == str5); // true
	

首先,堆中存放的是new创建的对象,垃圾回收也发生在这里

创建了几个对象的问题:在堆中使用new创建字符串的时候,首先要先去常量池中查询是否存在“hellotwo”,如果没有,则在常量池中创建一个“hellotwo”对象,然后堆中再创建一个常量池中的”hellotwo”对象的拷贝对象(所以第一个创建了两个对象)。且可以确定,new创建出来的对象一定存储在堆中,这里str3和str4指向的地址是堆中的对象。

:jdk1.7后常量池移动到了java堆中,在new的时候,不会再常量池中创建字符串,而是在常量池中生成一个对原字符串的引用。
此处还需要继续分析完善,涉及内存分配的其他知识,请自行补充知识。
如有优秀博文或者见解还请指出,这里参考多处,贴出来链接:
https://blog.csdn.net/zhyhang/article/details/17246223/
https://blog.csdn.net/u014039577/article/details/50377805

参考官方文档:https://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html#jdk7changes 主要介绍摘录如下:

Area: HotSpot
Synopsis: In JDK 7, interned strings are no longer allocated in the permanent generation of the Java heap, but are instead allocated in the main part of the Java heap (known as the young and old generations), along with the other objects created by the application. This change will result in more data residing in the main Java heap, and less data in the permanent generation, and thus may require heap sizes to be adjusted. Most applications will see only relatively small differences in heap usage due to this change, but larger applications that load many classes or make heavy use of the String.intern() method will see more significant differences.
RFE: 6962931

str3和str4不相等的问题:String对象内容在常量池只能有一个,而在堆中可以有多个,str3和str4引用各自指向不同的对象。

str3和str5不相等的问题:虽然在堆中创建对象之前会在常量池中检测是否存在,存在则直接创建,不存在则在常量池中创建后再拷贝到堆中,但是引用变量str3指向的还是堆中对象。

关于String的intern()方法:如果希望str3指向常量池中对象(常量池中存在这个对象),可以用str3调用intern()方法来返回常量池中相同Unicode的字符串常量的引用。如果有,则返回其的引用,如果不存在这个对象,则会在常量池中增加一个Unicode等于str3的字符串,并返回它的引用。str3和str5都指向常量池中的“hellotwo”,所以相同。

---------努力的分割线

第三个


	// num1、num2、127(一个)都存在栈中
	int num1 = 123;
    int num2 = 123;
    System.out.println(num1 == num2); // true

	// int1、int2存在栈中,126(一个)存在常量池中
	final int num3 = 126;
    final int num4 = 126;
    System.out.println(num3 == num4); // true
    

分析

num1和num2相等常量池中存放常量,且实现常量池的是基本类型的包装类,对应的基本数据类型是没有常量池的,JVM将基本数据类型的引用变量和值都放在栈空间中。

有自己常量池的包装类有:Byte,Short,Integer,Long,Character,Boolean。注意Byte,Short,Integer,Long,Character这5种整型的包装类也只是在对应值小于等于126时才可使用对象池,超出这个范围则由处理,下面第四个介绍。

126在常量池中常量池中存放常量(包括被final修饰的基本变量的值)

num3和num4相等:num3和num4指向的是常量池中的126。

---------努力的分割线

第四个

		
	// integ1、integ2 在栈中,127在Integer类的常量池中,且只有一个127常量
	Integer integr1 = 126;
    Integer integr1 = 126;
    System.out.println(integr1 == integr2); // true

	// integ3、integ4 在栈中,128在堆中创建有两个(这个时候常量池中没有,和第二个例子区分)。
    Integer integr3 = 128;
    Integer integr4 = 128;
    System.out.println(integr3 == integr4); // false

分析:

integr1、integr2相等:首先不属于基本类型,然后126在该类型的常量池的限制区间内(-128 <= integr1 && integr1 <= 127),所以存在Integer类的常量池中,且只有一个,两个引用变量指向的同一个127,所以相等。

integr3、integr4不相等:128超出整数在常量池的限制大小(integr3 > 127),这时候就需要在堆内创建对象,且堆中可以有多个。两个引用变量分别指向不同的对象,所以不相等。

---------努力的分割线

第五个


	Integer integr7 = new Integer(40);
    Integer integr8 = new Integer(20);
    Integer integr9 = new Integer(20);
    System.out.println((integr7 == (integr8 + integr9)); // true
    

为什么相等:integr8 和integr9进行相加会进行自动拆箱操作,数值相加得到40。这时Integer类型的integr7 和数值比较,integer7会自动拆箱转为int数值40,则(40 == 40)数值比较得到相等。


以上是通过一些常见的栗子来介绍内存分配的知识,自己简单记录一下以用总结复习,以后还需要继续深入学习。
路过的各位大佬,如有问题或争议还请提出,我将尽快修正,谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值