java String 字面值,new,intern,java8 Deduplication等

今天来总结一下String在jvm内存中的一些分配及其一些优化,包括最新的java8 update20才加入的deduplication特性,还有尚未发布的java 9中的compact特性

 

jvm中对象存在heap中,还有一块叫做String pool 的地方存放指向heap中字符串对象的指针

String s1 = "hello java";
String s2 = "hello java";
System.out.println(s1 == s2);  //true  说明s1和s2指向同一块内存地址

下面解释s1和s2的分配过程,

首先String s1 = "hello java"; ,这个是给s1分配字面值,jvm会先判断常量池中有没有引用指向堆中的一个字符串hello java,

如果没有就在堆中分配对象,然后线程堆栈的变量s1指向堆中的String对象,并且在String pool中维护一个引用指向这个String对象,

然后String s2 = "hello java",这个时候重复之前的过程,但是jvm发现常量池中已经有一个引用指向了堆中包含这个字面值的String对象,就直接在线程栈中分配了指向堆的新的引用S2,

结果如图下



 接下来看通过构造函数创建String

String s3 = new String("hello java");
System.out.println(s3 == s2);  //false  说明s3和s2 不是指向同一块内存地址

 s3是用new创建的对象,这个时候会忽略常量池中的引用,而直接在堆中新建一个对象,这种是不推荐的,下面是s3后的内存图



 


下面无论通过s3还是s1进行intern,返回的引用都是和s1相同,所以如果常量池中如果存在的话,intern返回的是引用和常量池中表记录的引用是一样的

String s4 = s3.intern();
String s5 = s1.intern();
System.out.println(s4 == s1);  //true
System.out.println(s5 == s1);  //true
//上面的图没有话,s4,s5指向的String对象和s1,s2一样

 java 8 update 20中如果加入-XX:+UseG1GC -XX:+UseStringDeduplication ,jvm将启动一个叫做Deduplication的优化,如果两个String对象中的char数组是一样的,则会回收掉其中一个,使两个对象share同一个char数组,注意必须启动java7新增的G1回收器
Deduplication和String intern不一样,前者是重用的char数组,并不会减少heap中的String对象数目
而后者可以直接重用现有的String对象
有关统计,大型java应用中25%的heap内存由String对象消耗,有近一半的String对象是重复的,也就是通过String的equals是返回true的,G1 garbage collector 会减少这种内存浪费
       
java9中新增的compcact机制可以让java中的char不要总是消耗2个byte,而是视情况而定,因为大多数情况其实一个char只需要8个bit就可以,也就是一个byte

参考如下:

http://openjdk.java.net/jeps/192

http://openjdk.java.net/jeps/254

 

后续可以通过分析字节码,利用java profile工具,分析gc log日志等方式更加细节的分析此类内存情况

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值