由intern深入String的内存模型
2017-09-06 23:17
399 查看
引言
Java里使用String的常量池(string pool),是对效率的妥协,是JVM中所模拟的缓存技术。
一、如何将String对象存储到常量池中:
1. 使用字面量常量声明(eg. String str = “Yeah”);
2. 使用intern进行赋值(JDK6-)/映射(JDK7+);
3. 利用编译器的自动优化(eg. String str = “Yeah” + “Man” //将YeahMan置入String pool);
二、String的不可变(immutable)性的探究:
在《Core Java》中对不可变字符串的描述是这样:“不可变字符串却有一个优点:编译器可以让字符串共享。Java的设计者认为共享带来的高效率远远胜过于提取、拼接字符串所带来的低效率。”
关于String的不可变性,是由于API中未对外提供相应的更改方法,使value的值恒定不可变。但我们可通过Java的动态反射机制,打破这种不可变性。
三、String.intern()所带来的变革(JDK6、JDK7):
String的常量池(String Pool)是存储在JVM内存中的,在JDK6之前(包含6),这一内存区域称为PermGen space(Permanent Generation space),JDK7则讲String Pool放在Heap中,JDK8进而一步移除了PermGen space 增设MetaSpace。以下将详细说明:
JDK6及之前版本,String Pool的实现
JDK7,String Pool的实现
JDK中通用实现,以JDK7为内存模型作图
Java里使用String的常量池(string pool),是对效率的妥协,是JVM中所模拟的缓存技术。
一、如何将String对象存储到常量池中:
1. 使用字面量常量声明(eg. String str = “Yeah”);
2. 使用intern进行赋值(JDK6-)/映射(JDK7+);
3. 利用编译器的自动优化(eg. String str = “Yeah” + “Man” //将YeahMan置入String pool);
二、String的不可变(immutable)性的探究:
在《Core Java》中对不可变字符串的描述是这样:“不可变字符串却有一个优点:编译器可以让字符串共享。Java的设计者认为共享带来的高效率远远胜过于提取、拼接字符串所带来的低效率。”
关于String的不可变性,是由于API中未对外提供相应的更改方法,使value的值恒定不可变。但我们可通过Java的动态反射机制,打破这种不可变性。
/** * 通过动态反射改变String的value值 * * @throws NoSuchFieldException * @throws IllegalAccessException */ private static void modifyStringValue() throws NoSuchFieldException, IllegalAccessException { String oriStr = new String("Hello"); System.out.println("oriStr store address: " + Integer.toHexString(System.identityHashCode(oriStr))); System.out.println(oriStr); Field field = String.class.getDeclaredField("value"); field.setAccessible(true); field.set(oriStr, "World".toCharArray()); System.out.println("newStr store address: " + Integer.toHexString(System.identityHashCode(oriStr))); System.out.println(oriStr); }
三、String.intern()所带来的变革(JDK6、JDK7):
String的常量池(String Pool)是存储在JVM内存中的,在JDK6之前(包含6),这一内存区域称为PermGen space(Permanent Generation space),JDK7则讲String Pool放在Heap中,JDK8进而一步移除了PermGen space 增设MetaSpace。以下将详细说明:
/** * 字符串常量池在JDK6/7中的区别 * output: * JDK6: false; * JDK7: true; */ public void stringPoolDiff() { // 等价于 String Hello = "Hello"; String world = "World"; String s1 = Hello + world; // 会被编译成 s1 = new StringBuilder().append(new String("Hello")).append(new String()).toString(); String s1 = new String("Hello") + new String("World"); s1.intern(); //jdk7 string pool中存储s1的引用 String s2 = "HelloWorld"; System.out.println(s1 == s2); }
JDK6及之前版本,String Pool的实现
JDK7,String Pool的实现
JDK中通用实现,以JDK7为内存模型作图
/** * 字符串常量池与堆空间 * output: * s1 storeAdr: 73c6c3b2 * s2 storeAdr: 48533e64 * s1_stringPool store address: 48533e64 */ @Test public void poolAndHeapStore() { String s1 = new String("Hello"); // string pool未存在“Hello”,先将“Hello”置入String pool,再进行对象创建 String s2 = "Hello"; // string pool已存在“Hello”,直接引用 String s1_stringPool = s1.intern(); System.out.println("s1 storeAdr: " + Integer.toHexString(System.identityHashCode(s1))); System.out.println("s2 storeAdr: " + Integer.toHexString(System.identityHashCode(s2))); System.out.println("s1_stringPool store address: " + Integer.toHexString(System.identityHashCode(s1_stringPool))); }
/** * 编译器自动优化字符字面量 * output: * true * true * false */ @Test public void compileAutoOptimize() { // 编译器自动优化,“Hello”和“World”不存入string pool,直接置入“HelloWorld” String s1 = "Hello" + "World"; String s2 = "HelloWorld"; // 验证"Hello"并未置入string pool String s3 = new String("Hel") + new String("lo"); s3.intern(); String s4 = "Hello"; // 只有字符常量拼接,编译器才进行优化 String s5 = "Hello".concat("World"); System.out.println(s1 == s2); System.out.println(s3 == s4); System.out.println(s2 == s5); }
/** * 常量字符串编译期才放入string pool * output: * false * true */ @Test public void poolAndHeapStore6() { // 常量字符串在编译期才放入string pool,s2通过s1而得到,属于运行时赋值,存于堆中; String s1 = "Hello"; String s2 = s1 + ""; String s3 = "Hello" + ""; System.out.println(s1 == s2); System.out.println(s1 == s3); }
相关文章推荐
- 深入理解Java String#intern() 内存模型
- 深入理解Java String#intern() 内存模型
- Java内存分析(3)——String的Intern方法详解
- string 的内存分配情况,以及intern()方法
- String内存模型
- Java-String.intern的深入研究
- 深入JVM系列(一)之内存模型与内存分配
- 深入理解JVM—JVM内存模型
- 深入理解JVM—JVM内存模型
- 通过反编译深入理解Java String及intern
- 深入JVM系列(一)之内存模型与内存分配
- 深入理解JVM—JVM内存模型
- 深入理解C++对象模型-对象的内存布局,vptr,vtable
- c/c++ 深入探讨数组内存模型
- 深入了解一下Redis的内存模型!
- c/c++ 深入探讨数组内存模型
- 深入理解JVM(一)——JVM内存模型
- 通过反编译深入理解Java String及intern
- 【转】深入理解JVM—JVM内存模型
- 深入解析String#intern