JVM中字符串常量池StringTable在内存中形式分析

    字符串常量池(StringTable)

      JVM中翻译字符串常量池(StringTable)为“String类型常量表”更合适,常量表它存储以双引号包住的String对象的地址引用,而不是String对象本身。通过StringTable可以实现相同内容的字符串共享。  在Java 8,StringTable是存放在内存堆中。(注意与Constant Pool的区别)。

    以下两类会纳入“字符串常量表StringTable”管理:

  • 已双引号包住形式申明的字符串String对象
  • String对象intern()方法获得的String对象

   而:其他方式如new String方式得到的String对象,不会纳入“字符串常量表StringTable”管理

   

下面分别展示和分析说明。

背景知识:通过java.lang.String的源代码分析,String类的内部是采用char [] 数组存放字符串的内容的。  (JDK9中实现已改为byte[]。鉴于JDK8使用者较多,下文仍以JDK8版本进行讨论

 

  • 双引号赋值

JVM中字符串常量池StringTable在内存中形式分析

  以上代码 执行过程:

  1. 由于是String类型,会有“字符串常量表StringTable”管理。 搜索已有的“字符串常量表”(上图中橙色区最下面的多个矩形)看看是否已存在值内容为“11”字符串对象。若存在直接执行第4步; 如不存在则执行第2,3步,4步(这里假设不存在)。
  2. 由于双引号“11”他是一个String的对象,既先创建new一个String对象(图中橙色区左上角的白色椭圆形)。而String对象需要一个char[]数组,则创建一个数组对象OOP既typeArrayOopDesc对象里面的内容为字符“11”。 然后把String对象的char[]指向这个typeArrayOopDesc对象。  到这步完成双引号“11”对象的创建。
  3. 将新建立的String对象加入到“字符串常量表”。 既“字符串常量表”中的一个元素,指向新new的String对象(上图中橙色区两个向上的蓝色箭头)。  到这步完成新String对象加入“字符串常量表”
  4. 将刚刚纳入“字符串常量表StringTable”管理的String对象地址,赋值给变量s1(上图左侧的蓝色箭头)。

 

  • new String方式

JVM中字符串常量池StringTable在内存中形式分析

 

  以上代码 执行过程:

  1. 由于是String类型,会有“字符串常量表StringTable”管理。 搜索已有的“字符串常量表”(上图中橙色区最下面的多个矩形)看看是否已存在值内容为“11”字符串对象。若存在直接执行第4步; 如不存在则执行第2,3步,4步(这里假设不存在)。
  2. 由于双引号“11”他是一个String的对象,既先创建new一个String对象(上图中橙色区中间的白色椭圆形)。而String对象需要一个char[]数组,则创建一个数组对象OOP既typeArrayOopDesc对象里面的内容为字符“11”。 然后把String对象的char[]指向这个typeArrayOopDesc对象。  到这步完成双引号“11”对象的创建。
  3. 将新建立的String对象加入到“字符串常量表”。 既“字符串常量表”中的一个元素,指向新new的String对象(上图中橙色区左下角的两个向上的蓝色箭头)。  到这步完成新String对象加入“字符串常量表”
  4. 执行上面代码中“new String”。 (可查看java.lang.String的源代码)既 创建一个新的String对象(上图中橙色区左上角的白色椭圆形),然后将刚刚纳入“字符串常量表StringTable”管理的String对象地址,赋值个这个新的String对象(上图中橙色区右上角的蓝色箭头)。
  5. 把第4步中创建的String对象,赋值给变量s1(上图左侧的蓝色箭头)。

 

  • 两句双引号(内容相同)

JVM中字符串常量池StringTable在内存中形式分析

以上第一句代码 执行过程:

  1. 由于是String类型,会有“字符串常量表StringTable”管理。 搜索已有的“字符串常量表”(上图中橙色区最下面的多个矩形)看看是否已存在值内容为“11”字符串对象。若存在直接执行第4步; 如不存在则执行第2,3步,4步(这里假设不存在)。
  2. 由于双引号“11”他是一个String的对象,既先创建new一个String对象(图中橙色区左上角的白色椭圆形)。而String对象需要一个char[]数组,则创建一个数组对象OOP既typeArrayOopDesc对象里面的内容为字符“11”。 然后把String对象的char[]指向这个typeArrayOopDesc对象。  到这步完成双引号“11”对象的创建。
  3. 将新建立的String对象加入到“字符串常量表”。 既“字符串常量表”中的一个元素,指向新new的String对象(上图中橙色区两个向上的蓝色箭头)。  到这步完成新String对象加入“字符串常量表”
  4. 在新new的String对象地址,赋值给变量s1(上图左侧下方蓝色箭头)。

以上第二句代码 执行过程:

  1. 由于是String类型,需要纳入“字符串常量表StringTable”管理。 搜索已有的“字符串常量表”(上图中橙色区最下面的多个矩形)看看是否已存在值内容为“11”字符串对象。(这里已经存在)。
  2. 从“字符串常量表StringTable”中找到的String对象地址,赋值给变量s2(上图左侧上方蓝色箭头)。

 

  • 两个new String

JVM中字符串常量池StringTable在内存中形式分析

以上第一句代码 执行过程:

  1. 由于是String类型,会有“字符串常量表StringTable”管理。 搜索已有的“字符串常量表”(上图中橙色区最下面的多个矩形)看看是否已存在值内容为“11”字符串对象。若存在直接执行第4步; 如不存在则执行第2,3步,4步(这里假设不存在)。
  2. 由于双引号“11”他是一个String的对象,既先创建new一个String对象(上图中橙色区最下面的白色椭圆形)。而String对象需要一个char[]数组,则创建一个数组对象OOP既typeArrayOopDesc对象里面的内容为字符“11”。 然后把String对象的char[]指向这个typeArrayOopDesc对象。  到这步完成双引号“11”对象的创建。
  3. 将新建立的String对象加入到“字符串常量表”。 既“字符串常量表”中的一个元素,指向新new的String对象(上图中橙色区左下角的两个蓝色箭头)。  到这步完成新String对象加入“字符串常量表”
  4. 执行上面代码中“new String”。 (可查看java.lang.String的源代码)既 创建一个新的String对象(上图中橙色区左上角下方的白色椭圆),然后将刚刚纳入“字符串常量表StringTable”管理的String对象地址,赋值个这个新的String对象(上图中橙色区左上角下方的白色椭圆)。
  5. 把第4步中创建的String对象,赋值给变量s1(上图左侧下方蓝色箭头)。

以上第二句代码 执行过程:

  1. 由于是String类型,会有“字符串常量表StringTable”管理。 搜索已有的“字符串常量表”(上图中橙色区最下面的多个矩形)看看是否已存在值内容为“11”字符串对象。(这里已经存在)。
  2. 执行上面代码中“new String”。 (可查看java.lang.String的源代码)既 创建一个新的String对象(上图中橙色区左上角上方的白色椭圆),然后从“字符串常量表”StringTable中找到的String对象地址,赋值个这个新的String对象(上图中橙色区左上角上方的白色椭圆)。
  3. 把第2步中创建的String对象,赋值给变量s2(上图左侧上方蓝色箭头)。