一个关于String的疑问

java里,String是本质还是一个immutable的对象,其值具体是由String类里的一个final char数组表示

private final char value[];

看了JDK源码才发现定义一个数组可以char[] value,也可以char value[]
参考:https://javaranch.com/journal/200409/ScjpTipLine-StringsLiterally.html
1 当执行:

一个关于String的疑问
文章图片
image.png
内存引用关系是这样的:

一个关于String的疑问
文章图片
image.png 2 当执行:

一个关于String的疑问
文章图片
image.png 内存引用关系是这样的:

一个关于String的疑问
文章图片
image.png 3 当执行:

一个关于String的疑问
文章图片
image.png
内存引用关系是这样的:

一个关于String的疑问
文章图片
image.png 而且文中关于垃圾收集:
Unlike most objects, String literals always have a reference to them from the String Literal Pool. That means that they always have a reference to them and are, therefore, not eligible for garbage collection.

不同于大多数对象,String总有一个来自于String常量池(String Literal Pool?)的引用,这意味着,String对象们总有一个引用持有着他们,因此不能被垃圾回收。
ok,既然定义一个不同的String就会在常量池中创建一个对堆中string的引用,并使得这个string对象很大程度上不被垃圾回收。
那么问题来了:不断地创建不同的String,是不是就撑爆了heap?:
static int i; public static void test(){ String c = "hello worldddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"; while (true){ String b = c+i; i++; System.out.println(b); }}

很明显我尝试了,并没有,执行到2亿次,也没有..
使用visualJVM来查看:

一个关于String的疑问
文章图片
image.png
查看metaspace,metaspace是jdk1.8之后增加的一个非heap的空间。
参考:https://segmentfault.com/a/1190000012577387
方法区移动到metaspace,constant pool似乎在heap?
一个关于String的疑问
文章图片
image.png
不管是heap,还是metaspace,内存似乎并没有显著平稳增加。
那么在进行字符串拼接的时候(“+”号运算符),到底发生了什么,到底有没有创建新的字符串到constant pool?

一个关于String的疑问
文章图片
image.png
Debug一下,总所周知,“+”号拼接字符串其实被编译为了StringBuilder进行拼接,debug结果显示的也是如此。看来采用StringBuilder并没有在常量池里创建多个String对象... 真的是如此吗?dump heap查看一下
首先用jps工具查出进程的vmid:
一个关于String的疑问
文章图片
image.png
(这里发现jdk提供的工具检测还是挺多的,还有jstat 查看jvm的各种状态,一个简单用法是jstat -snap vmid 见R大blog:http://rednaxelafx.iteye.com/blog/796343)
vmid为5430,接着dump heap:
一个关于String的疑问
文章图片
image.png
ok,分析一下hprof文件,看看到底有多少String:
一个关于String的疑问
文章图片
image.png
可以看到拼接了快750w次,String还只有1000个,其他都是jvm的路径之类的String,真正存在在内存里的似乎只有最后一个被拼接的String。。
【一个关于String的疑问】看来在进行拼接的时候还是进行了某些特殊的处理,代码有些分析不出来个所以然,猜测可能是jit在运行时有逃逸分析的优化?
所以我上面的测试代码可能就并没有不断的创建新的对象。
栈上分配,同步消除,标量替换
要知道经过标量替换,就不会生成新的对象了...
抑或是别的原因? 有时间再来验证。

    推荐阅读