由intern深入String的内存模型
来源:互联网 发布:微信app支付 php demo 编辑:程序博客网 时间:2024/05/17 00:18
引言
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); }
阅读全文
0 0
- 由intern深入String的内存模型
- 深入理解Java String#intern() 内存模型
- 深入理解 Java String.intern() 内存模型
- 由常量池 运行时常量池 String intern方法想到的(三)之String内存模型
- JVM-由常量池 运行时常量池 String intern方法想到的(三)之String内存模型
- 由常量池 运行时常量池 String intern方法想到的(四)之深入理解intern
- 节省内存的String.intern()
- String: 由intern看String
- String intern的深入理解(转)
- 深入java String.intern()
- 深入解析String#intern
- 深入解析String intern
- 深入解析String#intern
- 深入解析String#intern
- 深入解析String#intern
- 深入解析String#intern
- 深入解析String#intern
- 深入解析String#intern
- Linux下安装mysql出现的一些问题以及解决办法
- Grade HDU5038
- timequest静态时序分析学习笔记——基本概念
- 备份mysql远程数据库
- P
- 由intern深入String的内存模型
- 自己动手写操作系统(六)
- timequest静态时序分析学习笔记——命令约束
- CSS——div & span
- mybatis-3-mapper.dtd
- 13. Roman to Integer
- timequest静态时序分析学习笔记——工具使用
- Unity_JsonUtility的局限性_086
- 卷积神经网络学习笔记(一):CNN概况