JVM内部细节之三:字符串及字符串常量池
本人最近正在面试,然后注意到总是有公司喜欢考String的问题,如字符串连接有几种方式,它们之间有什么不同等问题;要不就是给一段代码问创建了几个对象。那么该不该问呢?我认为当面试有一定工作经验的求职者时还是应该问问这个问题的,应届生就不要为难他们了还是多考考底层基础比较好。下面我结合JVisualVM和javap这两个工具来详细解析下JVM内部是怎么处理String对象的。
一、字符串常量池(String Constant Pool)
字符串在java程序中被大量使用,为了避免每次都创建相同的字符串对象及内存分配,JVM内部对字符串对象的创建做了一定的优化,在Permanent Generation中专门有一块区域用来存储字符串常量池(一组指针指向Heap中的String对象的内存地址)。
创建字符串对象的几种形式:
(1)通过new方式如String s = new String("iByteCode")及string.intern()方法
(2)通过字面量的形式如String s = "aaaaa"
(3)字面量+字面量如String s = "bbbb" + "ccccc"
(4)字面量+变量如String s1 = "dddd";String s = "eeeee"+s1
假设刚开始字符串常量池为空,那么对于第一种创建方式,JVM内部是怎么处理的,这里也有一个面试题就是一共创建了几个对象,在这里答案是两个,为什么说是两个呢?一个是字符串字面量本身(可以通过string.intern()方法来取得,下图中常量池所指向的字符串对象),一个是单独的字符串对象,Heap视图如下所示:

看下面的代码:
public class StringConstantPoolTester {
//private String s1 = new String("iByteCode");
public static void main(String[] args) throws Exception {
String s1 = new String("iByteCode");
System.out.println(s1);
CyclicBarrier barrier = new CyclicBarrier(2);
barrier.await();
}
}
那么怎么来验证上面的结论的正确性呢?我们可以通过JVisualVM来Heap dump功能来实现,通过OQL语言来查询Heap内值为iByteCode的字符串对象的个数就可以确定上面的代码到底创建了几个对象。执行结果如下图所示:

这里有一点要注意,对于通过new方式创建的String对象,每次都会在Heap上创建一个新的实例,但是对于字符串字面量的形式,只有当字符串常量池中不存在相同对象时才会创建。
第二种方式不用说,相当于第一种方式中的字面量部分。
第三种和第四种方式会怎样创建字符串对象,可以通过javap和JVisualVM来验证,下面通过一段代码来验证:
public class StringConstantPoolTester {
//private String s1 = new String("iByteCode");
public static void main(String[] args) throws Exception {
String s1 = new String("iByteCode");
String s2 = "bbbb" + "ccccc";
String s3 = "dddd" + s2;
System.out.println(s3);
CyclicBarrier barrier = new CyclicBarrier(2);
barrier.await();
}
}
这段代码的bytecode输出如下:

对于第三种形式String s2 = "bbbb" + "ccccc",在main方法字节码的第10-12可以看到在JVM里直接通过ldc指令将指向bbbbccccc字符串字面量的引用的值放入到Operand Stack顶,然后存入到Local variable Array的第二个slot位。同时可以通过JVisualVM验证结论的正确性,由于篇幅问题这里省略。
对于第四种形式String s3 = "dddd" + s2,在main方法字节码的13-32可以看到在JVM里面创建了两个字符串字面量dddd和ddddbbbbccccc,并且调用StringBuilder对字符串进行连接。
二、参考资料:
http://theopentutorials.com/tutorials/java/strings/string-literal-pool/
JVM内部细节之三:字符串及字符串常量池的更多相关文章
- JVM内部细节之二:偏向锁(Biased Locking)
在前面一片文章<JVM内部细节之一:synchronized关键字及实现细节>中已经提到过偏向锁的概念,在理解什么是偏向锁前必须先理解什么是轻量级锁(Lightweight Locking ...
- JVM内部细节之一:synchronized关键字及实现细节(轻量级锁Lightweight Locking)
在C程序代码中我们可以利用操作系统提供的互斥锁来实现同步块的互斥访问及线程的阻塞及唤醒等工作.然而在Java中除了提供Lock API外还在语法层面上提供了synchronized关键字来实现互斥同步 ...
- JVM(19)之 Class文件常量池
开发十年,就只剩下这套架构体系了! >>> 在上一博文Class文件中,我们了解了Class文件的一些基础知识.他的整个内部结构就是一张很大的表,我们就是从这张表入手,一一分析每 ...
- JVM字符串常量池StringTable
String的基本特性 String:字符串,使用一对""引起来表示. String sl = "hello"://字面量的定义方式: String s2 = ...
- 从字符串到常量池,一文看懂String类设计
从一道面试题开始 看到这个标题,你肯定以为我又要讲这道面试题了 // 这行代码创建了几个对象? String s3 = new String("1"); 是的,没错,我确实要从这里 ...
- Java String:字符串常量池(转)
作为最基础的引用数据类型,Java 设计者为 String 提供了字符串常量池以提高其性能,那么字符串常量池的具体原理是什么? 字符串常量池的设计思想是什么? 字符串常量池在哪里? 如何操作字符串常量 ...
- 8.StringTable(字符串常量池)
一.String的基本特性 String:字符串,使用一对 "" 引起来表示 String s1 = "atguigu" ; // 字面量的定义方式 Strin ...
- java中字符串“不可变性”的破坏,使用反射破坏final属性。以及涉及到字符串常量池的问题。
大家都清楚java中String类是不可变的,它的定义中包含final关键字.一旦被创建,值就不能被改变(引用是可以改变的). 但这种“不可变性”不是完全可靠的,可以通过反射机制破坏.参考一下代码: ...
- 常量池之字符串常量池String.intern()
运行时常量池是方法区(PermGen)的一部分. 需要提前了解: 1. JVM内存模型. 2. JAVA对象在JVM中内存分配 常量池的好处 常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现 ...
随机推荐
- php变量和字符串连接符——点
连接符——点,本身也是一种运算符.它真正的名字应该叫“字符运算符”.作用是把两个字符串连接起来. echo 字符 . 变量 . 字符; //点号把三个值连接成为一个,运行正常. 例: 1.字符串+变 ...
- KBMMW 的日志管理器
kbmmw 4.82 最大的新特性就是增加了 日志管理器. 新的日志管理器实现了不同类型的日志.断言.异常处理.计时等功能. 首先.引用kbmMWLog.pas 单元后,系统就默认生成一个IkbmMW ...
- Java实现哈夫曼编码和解码
最近无意中想到关于api返回值加密的问题,譬如我们的api需要返回一些比较敏感或者重要不想让截获者得到的信息,像如果是做原创图文的,文章明文返回的话则有可能被抓包者窃取. 关于请求时加密的方式比较多, ...
- 移动端自动化openatx开源项目介绍,pytest并发测试框架结合
开头 相信不少用过appium的同学,对于使用appium的一些体会与感受是否与我相似 1. appium启动服务和app程序非常慢 2. appium多线程并发需要启动多个服务 3. appium必 ...
- android_serialport_api hacking
/************************************************************************************ * * android_se ...
- 安装依赖库的方法-linux
前言 使用linux系统的过程中,项目可能需要用到各种依赖库或者工具包,本文对库或者包的安装方法进行概述. 具体方法 如何安装各种依赖库或者工具包:1)直接使用apt-get install进行安装, ...
- 批量读取文件matlab
前言 工程实现的过程中经常需要依次读取文件夹中的图像(或者其他文件),本文就对此进行实现. 代码 % /************************************************ ...
- HDU 5372 Segment Game (树状数组)
题意是指第i此插入操作,插入一条长度为i的线段,左端点在b[i],删除某一条线段,问每次插入操作时,被当前线段完全覆盖的线段的条数. 题解:对于新插入的线段,查询有多少个线段左端点大于等于该线段的左端 ...
- hibernate 1-1(具体解释)
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/qilixiang012/article/details/27870343 域模型 关系数据模型: 依 ...
- tomcat源码阅读之StandardWrapper解析
一.UML图: 1.Tomcat中Wrapper代表一个独立的servlet实例,StandardWrapper类是Wrapper接口的标准实现类,StandardWrapper类还实现了Selvle ...