StringTable(串池)详解

本文详细介绍了Java中的StringTable(串池),包括常量池与串池的关系,字符串变量和常量拼接的原理,以及不同JDK版本下intern()方法的行为。讲解了StringTable的位置变迁,从JDK1.6的永久代到JDK1.8的堆空间,并探讨了StringTable的垃圾回收和性能调优,包括调整hashTable桶的个数以减少冲突,提高查找效率。

1. 常量池与串池的关系

  • 1:先把这段代码的二进制字节码进行反编译

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1UPTOVZm-1651717989295)(https://note.youdao.com/yws/res/e/WEBRESOURCEd526d64244e564378b73df4cf167b4ce)]

  • 2:反编译过后我们看类方法定义部分、虚拟机指令、常量池
    类方法定义
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gLJT1A9F-1651717989296)(https://note.youdao.com/yws/res/6/WEBRESOURCEb7a4d911eb3011c3ff596a432d67c4d6)]

虚拟机指令
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ahO6gFBQ-1651717989296)(https://note.youdao.com/yws/res/f/WEBRESOURCEe107d598706cf4615a7796f6dc5fbd0f)]

常量池

在代码运行的过程中,常量池中的信息,都会被加载到运行时常量池中,我们可以看到这时a b ab 都是常量池中的符号,还没有变成Java字符串对象,只有在执行到具体引用它的那行代码上才会变成对象(懒惰模式),比如:String s1 = “a”;其实它代表的就是虚拟机指令中的:0: ldc #2 // String a

对于上面的补充:在开始创建出一个字符串对象的时候,还需要做一件事情—准备一块空间:StringTable[](串池) 刚开始它时空的没有内容,先去常量池中找到a这个符号,然后把它作为一个key去StringTable[]中找,看有没有取值相同的key,没有的话就会创建这个字符串"a"并且将它放入串池。

StringTable[]在结构上其实是一个hash表,且长度固定,不能扩容
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9l4QDVDp-1651717989297)(https://note.youdao.com/yws/res/6/WEBRESOURCEf563f6fb4046ae12a9f0b6ba4dc675a6)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3UFISJNk-1651717989298)(https://note.youdao.com/yws/res/4/WEBRESOURCEcdaa0c774d48fe36060a210d6c5f0784)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qcHrEWKn-1651717989299)(https://note.youdao.com/yws/res/b/WEBRESOURCEd525bd7cad4c76af45e2e3ddf32e29db)]

  • tip

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uIfFO3Pd-1651717989299)(https://note.youdao.com/yws/res/2/WEBRESOURCEe53b2c39e179b2b313b85edd02369ee2)]

这个 LocalVariableTable其实就是当前当前正在运行的这个main方法的栈帧运行时的局部变量表,其里面存储的就是局部变量

下图中的虚拟机指令的作用就是把生成的字符串对象存入这个局部变量表中去,且在表中每个变量都有编号。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-52Vmn7HB-1651717989299)(https://note.youdao.com/yws/res/5/WEBRESOURCEa6669ed476272715b68b62a9a3d890e5)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ozhhYb2M-1651717989300)(https://note.youdao.com/yws/res/0/WEBRESOURCEd58be8c7c67d85368fe3cf1272717b20)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-I1F1Kpha-1651717989302)(https://note.youdao.com/yws/res/b/WEBRESOURCE736855dead8a6330e516efd7e070493b)]

2. 字符串【变量】拼接的原理 StringBuilder

下图中的s4,首先给出结论,通过将二进制字节码反编译我们可以得出图中圈出部分结论

![\[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PpabUICY-1651717989303)(https://note.youdao.com/yws/res/b/WEBRESOURCE87d705773f97fa577281e2ae1227d31b)\]](https://img-blog.csdnimg.cn/f8089247a96c4af8a8acdd1023bafc4a.png)

aload指令和astore指令相反,aload是从局部变量表中取,astore是存
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XfBQ9GOj-1651717989304)(https://note.youdao.com/yws/res/d/WEBRESOURCEea69441f239f2dcde9eea17a2a28dc0d)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ydAp7eK7-1651717989305)(https://note.youdao.com/yws/res/a/WEBRESOURCE0821426b4efec10d665e96106a15a71a)]

  • 通过下图得出为什么会有上述结论

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WbX9Q55O-1651717989305)(https://note.youdao.com/yws/res/5/WEBRESOURCE933bcbdbe615f9ca6dc56c09ead3f145)]

3. 编译期优化(字符串【常量】拼接的原理)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bc9uQdl1-1651717989306)(https://note.youdao.com/yws/res/5/WEBRESOURCE00b2efe5da01a96d91d53b821fb0cf55)]

  • 同上,我们直接开看反编译结果

关键点:这里的虚拟机指令ldc #4其实就是源码运行到String s5 = “a” + "b"这里,先在常量池中找到"ab"字符串,然后把他们作为key去串池stringTable[]中寻找,发现有相同的,因此就直接使用串池中的了,所以s3 == s5 的值是true
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M3h6A9LW-1651717989306)(https://note.youdao.com/yws/res/4/WEBRESOURCE8d029d163b73cb361db85f5484f17994)]

4. 字符串延迟加载

首先给出结论:不是一下子把这些字符串放入串池,而是执行一行代码,遇到一个串池中没有的字符串对象就将其放入到串池中去。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4SwmoROj-1651717989307)(https://note.youdao.com/yws/res/9/WEBRESOURCEa598bf7f8c76aeece966e53893fcde89)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eInqji6i-1651717989307)(https://note.youdao.com/yws/res/7/WEBRESOURCE7e8338edcfba0148d4b7a5d4523e0c67)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dn0YA0hD-1651717989308)(https://note.youdao.com/yws/res/3/WEBRESOURCEf7b87555fa39c672084bb390d2291403)]

5. 可使用intern方法,主动将串池中还没有的字符串对象放入串池

5.1 jdk1.8、1.7以后的intern,将这个字符串对象尝试放入串池,如果有则并不会放入,如果没有则放入串池,并且会把串池中的对象返回

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-voJRCKwY-1651717989308)(https://note.youdao.com/yws/res/c/WEBRESOURCE380dab011876bc3b4b0e147c901f7a2c)]

5.2. jdk1.6的intern,将这个字符串对象尝试放入串池,如果有则并不会放入,【【如果没有则会把此对象复制一份再 放入串池】】,并且会把串池中的对象返回

6. StringTable位置

jdk1.6 串池用的是【永久代】。
jdk1.8 串池用的是【堆空间】。

  • ------jdk1.6下

通过以下代码来测试位置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KECbUuyL-1651717989309)(https://note.youdao.com/yws/res/b/WEBRESOURCEb2a4ceb2b394ecffb5eecf7803e4b88b)]

通过下面的这个参数来设置永久代的最大内存大小(便于测试)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BcvWcDqW-1651717989309)(https://note.youdao.com/yws/res/0/WEBRESOURCEff4b9ff0b2118c05296b1f0f8acdf750)]

运行后的结果:显示为永久代内存溢出

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zogdVVuH-1651717989309)(https://note.youdao.com/yws/res/3/WEBRESOURCE9d10f5f8748a7be1b54c9fe3ef98b773)]

  • ------jdk1.8下

通过以下代码来测试位置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AUwkOc2k-1651717989311)(https://note.youdao.com/yws/res/a/WEBRESOURCE875be518457af3a81b2580d95849220a)]

通过下面这个参数来设置堆的最大内存(便于测试)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3eRb8msP-1651717989311)(https://note.youdao.com/yws/res/3/WEBRESOURCE1da9920ff7318b7aa0d88e3522f9be33)]

运行的结果不是我们想象的那样报堆内存溢出的错误,这里的错误:OutOfMemory: GC overhead limit exceeded

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MLU3qa0A-1651717989311)(https://note.youdao.com/yws/res/a/WEBRESOURCE1ba274673b7aaba1a5a7365e9147ab6a)]

通过官方文档的一个参数(如下图)可知出现那个错误的原因:如果98%的时间花在了垃圾回收上,但是只有2%的堆空间被回收了,会认为当前jvm已经无可救药了,这个时候就不会尝试垃圾回收了,就会报这个错误,而不是报堆空间不足的错误,为了掩饰这个现象我们需要加入这个参数来把 这个关掉。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XTjyD2A4-1651717989312)(https://note.youdao.com/yws/res/2/WEBRESOURCE6eddb9e98de17b21a6728c83f53ad062)]

接上述:我们添加 这个参数且运行后,报的是堆空间溢出的错误。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cu29mEYS-1651717989313)(https://note.youdao.com/yws/res/1/WEBRESOURCE605405f5607353d65af34bcb018ddce1)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y3t1PgR5-1651717989313)(https://note.youdao.com/yws/res/a/WEBRESOURCE6e019e46dda4b5501c2fa3997681b0aa)]

7. StringTable垃圾回收

  • 垃圾回收只有在内存不足的时候才会触发

先看这几个参数

-Xmx10m 设置堆空间的大小为10m

-XX:+PrintStringTableStatistics 打印字符串表的统计信息,通过它我们可以看到串池中字符串的个数包括大小信息

-XX:+PrintGCDetails -verbose:gc 打印垃圾回收的信息、堆内存占用的信息,如果发生垃圾回收的话它会把垃圾回收的次数、时间打印出来。

为这个测试demo加上这几个参数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H4E9RCjb-1651717989313)(https://note.youdao.com/yws/res/6/WEBRESOURCEaaedd9c807d2a54f8150e22db9e50906)]

先看这段代码,这是段没有实际操作的代码,我们看他的输出结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2WCz76Iw-1651717989313)(https://note.youdao.com/yws/res/2/WEBRESOURCE7f4b7087d58a6fab47fee180ce85e472)]

打印出的符号表(属于常量池的一部分,类的字节码中的类名、方法名、变量名等,他们也是需要读入内存中将来以被查表的方式去转换的)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-msR2zRq5-1651717989314)(https://note.youdao.com/yws/res/c/WEBRESOURCEc8c24f63a1adebe6c7f96a1bd3a694fc)]

打印出的StringTable的信息,其底层的实现是hashtable,数组加链表,其中:数组的个数称为“桶”,桶的个数就是下图中的Number Of buckets。

下图可见:桶的个数默认是60013,存储的对象的个数(键值对的个数)为:1754,字符串的常量的个数(串池中的字符的个数literals)为:1754

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JTh4kkS4-1651717989315)(https://note.youdao.com/yws/res/b/WEBRESOURCEf716da98182e1bcf23f4f42bd9cc075b)]

------改动一下上面的代码,我们创建字符串对象并且让其进入串池

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iWS07Htf-1651717989315)(https://note.youdao.com/yws/res/d/WEBRESOURCEb120435d3dea3ce4af176caef8ef549d)]

------其运行结果是:可以明显的看到新的字符串的个数被加入StringTable中的,但是仅有的100个字符串不至于引发垃圾回收(通过这次运行打印没有看到上面过的那个参数打印出垃圾回收的信息)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cNVCqVFh-1651717989316)(https://note.youdao.com/yws/res/8/WEBRESOURCE1cbe4a52a34d6ad46a8a10b5dd48e5f8)]

-----如果我们改动一下代码,将10000个字符串放入串池中去,我们再看运行结果:可以看到串池中的字符串个数为7000+,说明发生了垃圾回收,也确实我们看到打印出了垃圾回收的信息(如下二图)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TWyylh5H-1651717989317)(https://note.youdao.com/yws/res/f/WEBRESOURCE1a465723e6ecde4881e723a582fd2d2f)]
在这里插入图片描述

8. StringTable性能调优(其实主要是调整hashTable桶的个数)

StringTable的底层是hash表,其性能是根据其大小相关的,如果hash表桶的个数(数组的个数)比较多,相对来说比较分散,发生hash碰撞的几率就会减小,查找的速率也会更快,反之,桶的个数较少,发生hash碰撞的概率较大,链表更长,查找的速率也会更慢。

8.1. 方式一:通过调整参数-XX:StringTableSize=桶个数

  • 先给出8.1的总结:如果你的这个系统中常量的个数比较多的话,可以适当的把StringTable的桶的个数调的比较大,可以有一个更好的hash分布,减少hash冲突,让StringTable的串池的效率有个明显的提升

------通过以下测试demo:读入一个文档,其中有40万+行单词

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Sv7yVCYT-1651717989318)(https://note.youdao.com/yws/res/c/WEBRESOURCEc6dce36702034673c8e91dc06c9b308c)]

------此时我们通过用虚拟机参数对其调整如图一所示,运行结果为:

花费时间为0.4秒,为什么会这么快呢,我们再通过图三看一下StringTable的统计信息,可以发现桶的个数调整为了20万,也就是这40万+的单词分在了20万个桶里面,因此这效率是非常快的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WMv2P0R8-1651717989319)(https://note.youdao.com/yws/res/f/WEBRESOURCE06ebce45e353b0f1485177ee4f4b890f)]


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QvohhjAG-1651717989320)(https://note.youdao.com/yws/res/e/WEBRESOURCEb82965a6f8c183fcb1b8cd96dabbfbce)]


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2ZRR5Azl-1651717989320)(https://note.youdao.com/yws/res/0/WEBRESOURCEc95f9c922059686e2458839481eafec0)]

------如果我们去掉对桶的个数的修改,让其个数为默认值,则运行结果为:可以看到时间为0.6秒,默认的桶的个数为:60013

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3qIyAZwy-1651717989321)(https://note.youdao.com/yws/res/9/WEBRESOURCE88a9537c4fcee2697b4e7808e70a34e9)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EPGyEr1z-1651717989321)(https://note.youdao.com/yws/res/6/WEBRESOURCE11454c67dc866758013bc5dd3af488b6)]

------如果我们把桶的值调小(规定范围为:1009~~2305843009213693951),可以看到运行结果很慢,变成了12秒左右

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YRuElrV3-1651717989322)(https://note.youdao.com/yws/res/4/WEBRESOURCE54ff5601a27804edbcabe7cd7d086874)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YnpiRNK5-1651717989322)(https://note.youdao.com/yws/res/0/WEBRESOURCE8cf88a06a8c8171debf22b746879b370)]

8.2. 考虑将字符串对象是否入池(采用intern()方法,可以去除重复的地址,相同的地址intern()后再串池中只会寸尺一份,减少内存的占用)

------我们通过下面这个demo演示,我们这个demo和8.1的区别就是我们这把这个文档循环读取了10词,就是把8.1中创建的对象的个数这里再×10并且存放在list中,且一直是存放在堆中,没有被垃圾回收掉,注意我们这里的29是没有使用intern的,所以确实是和8.1相比乘了10的对象个数

运行后我们看内存占用:加起来共占了80%多的堆内存
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UYqxKprW-1651717989323)(https://note.youdao.com/yws/res/f/WEBRESOURCE714c5ce2a955c121259fb7c9ea49894f)]

------和上面不同的是我们这里用了intern() 方法,这说明虽然我们这里创建的字符串对象的个数和上面一样,但是我们除了第一次循环创建,另外9此循环创建的字符串对象都因为在串池中已经有对应的字符串常量存在而没有存放在堆中,因此后面创建的这些都被垃圾回收掉了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-94I1SaDd-1651717989324)(https://note.youdao.com/yws/res/4/WEBRESOURCEe39b718b6f436c36e1093a779da05b94)]

运行后我们看内存占用:加起来共占了30%多的堆内存,明显占用的内存量大大下降
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yjff9unY-1651717989324)(https://note.youdao.com/yws/res/a/WEBRESOURCE306e8f92d4e1d4f28b5bbdac641b2cca)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值