本人最近正在面试,然后注意到总是有公司喜欢考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内部细节之三:字符串及字符串常量池的更多相关文章

  1. JVM内部细节之二:偏向锁(Biased Locking)

    在前面一片文章<JVM内部细节之一:synchronized关键字及实现细节>中已经提到过偏向锁的概念,在理解什么是偏向锁前必须先理解什么是轻量级锁(Lightweight Locking ...

  2. JVM内部细节之一:synchronized关键字及实现细节(轻量级锁Lightweight Locking)

    在C程序代码中我们可以利用操作系统提供的互斥锁来实现同步块的互斥访问及线程的阻塞及唤醒等工作.然而在Java中除了提供Lock API外还在语法层面上提供了synchronized关键字来实现互斥同步 ...

  3. JVM(19)之 Class文件常量池

    开发十年,就只剩下这套架构体系了! >>>   在上一博文Class文件中,我们了解了Class文件的一些基础知识.他的整个内部结构就是一张很大的表,我们就是从这张表入手,一一分析每 ...

  4. JVM字符串常量池StringTable

    String的基本特性 String:字符串,使用一对""引起来表示. String sl = "hello"://字面量的定义方式: String s2 = ...

  5. 从字符串到常量池,一文看懂String类设计

    从一道面试题开始 看到这个标题,你肯定以为我又要讲这道面试题了 // 这行代码创建了几个对象? String s3 = new String("1"); 是的,没错,我确实要从这里 ...

  6. Java String:字符串常量池(转)

    作为最基础的引用数据类型,Java 设计者为 String 提供了字符串常量池以提高其性能,那么字符串常量池的具体原理是什么? 字符串常量池的设计思想是什么? 字符串常量池在哪里? 如何操作字符串常量 ...

  7. 8.StringTable(字符串常量池)

    一.String的基本特性 String:字符串,使用一对 "" 引起来表示 String s1 = "atguigu" ; // 字面量的定义方式 Strin ...

  8. java中字符串“不可变性”的破坏,使用反射破坏final属性。以及涉及到字符串常量池的问题。

    大家都清楚java中String类是不可变的,它的定义中包含final关键字.一旦被创建,值就不能被改变(引用是可以改变的). 但这种“不可变性”不是完全可靠的,可以通过反射机制破坏.参考一下代码: ...

  9. 常量池之字符串常量池String.intern()

    运行时常量池是方法区(PermGen)的一部分. 需要提前了解: 1. JVM内存模型. 2. JAVA对象在JVM中内存分配 常量池的好处 常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现 ...

随机推荐

  1. windows开机自动登录

     控制台输入control userpasswords2 ,去掉下图中的√,输入登陆所用用户名密码即可.

  2. hdu-5810 Balls and Boxes(概率期望)

    题目链接: Balls and Boxes Time Limit: 2000/1000 MS (Java/Others)     Memory Limit: 65536/65536 K (Java/O ...

  3. Xcode C++ and Objective-C refactoring

    Is there a way to refactor mixed C++/Objective-C code in Xcode ?? I am writing a game using Cocos2D ...

  4. 电脑技巧合集 - imsoft.cnblogs

    ● 如何制作网页● 教你建一个别人打不开的文件夹 ● 只改一个值!马上加快宽带上网速度 ● 在电脑右下角显示你的名字● XP系统如何加快开机速度● 连接宽带时出错表示的意思 ● 恢复丢失数据的方法● ...

  5. 《DSP using MATLAB》Problem 4.3

    代码: %% ------------------------------------------------- %% 1 x(n)=2δ(n-2)+3u(n-3) %% -------------- ...

  6. 将string str中的str转换成字符数组

    #include <iostream> #include <map> #include <string.h> using namespace std; int ma ...

  7. tiny4412-Uboot启动分析

    一.从本质上将,引导转载程序至少应提供以下功能 (1)设置和初始化RAM (2)初始化一个串口 (3)检测机器类型(machine type) (4)设置内核标签列表(tag list) (5)调用内 ...

  8. SQL Support and Workarounds

    此文章来自官方文档,说明了,对于不支持pg 标准的sql 查询的变通方法,实际使用的时候有很大的指导意义 As Citus provides distributed functionality by ...

  9. nyoj 一笔画问题

    一笔画问题 描述 zyc从小就比较喜欢玩一些小游戏,其中就包括画一笔画,他想请你帮他写一个程序,判断一个图是否能够用一笔画下来. 规定,所有的边都只能画一次,不能重复画.   输入 第一行只有一个正整 ...

  10. JUC线程池之 线程池的5种状态:Running, SHUTDOWN, STOP, TIDYING, TERMINATED

    线程池有5种状态:Running, SHUTDOWN, STOP, TIDYING, TERMINATED. 线程池状态定义代码如下: private final AtomicInteger ctl ...