聊聊javastring.intern背后你不知道的知识

author author     2022-12-26     111

关键词:

聊聊Java String.intern 背后你不知道的知识

导读:String.intern是一个JDK中的常用方法,通常用于缓存字符串,优化内存使用,然而频繁使用该方法也会导致别的问题,本文从该方法的实现入手,深入分析了可能出现的问题和解决方案。

Java的 String类有个有意思的public方法:

public String intern()

返回标准表示的字符串对象。String类维护私有字符串池。

调用此方法时,如果字符串池已经包含等于此字符串对象的字符串(通过equals方法确定),则返回池中的字符串。 否则,将此String对象添加到池中,并返回对此String对象的引用。

这个功能为String提供了字符串池,我们可以使用它来优化内存。 但是,这有一个缺点:在OpenJDK中,String.intern()是本地方法,它实际上调用了JVM的相关方法来实现该功能。这样实现的原因是,当VM和JDK代码必须就特定String对象的标识达成一致时,String interning就必须是JDK-VM接口的一部分。

这样的实现意味着:
1.您需要在每个intern调用使用JDK-JVM接口,这会浪费CPU。
2.性能受本地HashTable实现的影响,可能落后于高性能Java版本,特别是在并发访问的情况下。
3.由于Java Strings是来自VM的引用,因此它们成为GC root set的一部分。 在许多情况下,这需要在GC停顿期间执行额外的工作。

吞吐量实验

我们可以构建简单的实验来说明问题。 使用HashMap和ConcurrentHashMap实现intern方法,这为我们提供了一个非常好的JMH基准:
技术图片
技术图片
该测试试图在很多字符串上执行intern方法,但实际的intern仅在第一次遍历循环时发生,之后只访问map中的字符串。 size参数用于控制我们intern的字符串数量,从而限制我们正在处理的字符串表大小。 对于intern来说,通常都这样使用。

使用JDK 8u131运行它:
技术图片
可以看出 String.intern()明显更慢。慢的原因在于本地实现,这在perf record -g中清晰可见:
技术图片
虽然JNI转换成本相当高,但似乎在StringTable实现上也花了相当多的时间。 使用 -XX:+PrintStringTableStatistics,将输出如下内容:
技术图片
注意最后一行,平均每个bucket 16个元素表示已经过载。 更糟糕的是,字符串表不可调整大小(虽然有实验工作使它们可以调整大小,但是因为“其他原因”而被移除)。 通过设置更大的-XX:StringTableSize可能会减轻该问题:
技术图片
然而这只能暂时缓解问题,因为你必须提前做好规划。 如果盲目地将String表大小设置为较大值,并且不使用它,则会浪费内存。 即使您使用很大的StringTable,JNI本地调用仍然会消耗CPU。

GC停顿实验

本地字符串表最大问题在于它是GC root的一部分。也就是说,它应该需要垃圾收集器进行特殊扫描/更新。 在OpenJDK中,这意味着在暂停期间额外工作。 实际上,对于Shenandoah(译者注:对于ZGC也如此),暂停主要依赖于GC root set大小,在String表中存在1M记录会导致以下结果:
技术图片
因为我们在root set中添加了内容,每次暂停会增加13ms。

某些GC实现仅在完成重要操作时执行String表清理。 比如,如果不进行卸载类,从JVM角度来看清理String表是没有意义的(因为加载的类是intern字符串的主要来源)。 因此,此工作负载在G1和CMS中会也会表现出有趣的行为:
技术图片
用CMS跑一遍:
技术图片
看起来结果还可以。 遍历重载的字符串表需要一段时间。 蛋疼的事情会在使用-XX:-ClassUnloading禁用类卸载后发生。你猜猜接下来会发生什么:
技术图片
FULL GC! 对于CMS,假设用户会调用System.gc(),使用ExplicitGCInvokesConcurrentAndUnloadsClasses会缓解这一情况。

意见

在假设改进内存占用空间或低级==优化的情况下,我们讨论了实现intern的方法。有关Java String的更多详细信息,可以参考我的演讲“java.lang.String Catechism”。

对于OpenJDK,String.intern()是本机JVM字符串表的代理,使用它需要注意:吞吐量,内存占用,暂停时间等问题。 很容易低估这些问题的影响。 手动控制的intern工作更加可靠,因为它们在Java端工作,只是普通Java对象,通常更容易调整大小,并且在不再需要时也可以完全丢弃。 GC辅助字符串去重复数据(http://openjdk.java.net/jeps/192)确实可以减少很多问题

几乎在在我们进行每个项目中,从热路径中删除String.intern(),或者用手动方式替代它,都有很大的性能提升。 不要无脑使用String.intern(),好吗?

原文地址:

https://shipilev.net/jvm/anatomy-quarks/10-string-intern/

本文作者Aleksey Shipilёv,由方圆翻译。转载本文请注明出处,欢迎更多小伙伴加入翻译及投稿文章的行列,详情请戳公众号菜单「联系我们」。

参考阅读:

  • 为何服务器QPS上不去?Java线程调优权威指南
  • C++ Python PHP Java NodeJS性能大PK,结果PHP7是最……
  • 一文读懂Java 11的ZGC为何如此高效
  • 5分钟学会Java 9~Java11的七大新特性
  • Java性能优化指南及唯品会的实战

技术原创及架构实践文章,欢迎通过公众号菜单「联系我们」进行投稿。转载请注明来自高可用架构「ArchNotes」微信公众号及包含以下二维码。

高可用架构

改变互联网的构建方式

技术图片

你不知道的js来聊聊this(代码片段)

为什么要使用this?什么是this?来看一段代码functionidentify()returnthis.name.toUpperCase();functionspeak()vargreeting="Hello,I‘m"+identify.call(this);console.log(greeting);varme=name:"Kyle";varyou=name:"Reader" 查看详情

聊聊ios实现渐变色文本以及可能你不知道的细节(代码片段)

👇👇关注后回复 “进群” ,拉你进程序员交流群👇👇前言前段时间工作中,产品给了一个实现渐变色文本,并且是放到富文本里面的需求。插入到富文本这里先不说,无非就是生成这个渐变Lab... 查看详情

粪菌移植的背后,肠道菌那些你不知道的事儿

近日16岁男孩通过粪菌移植治疗自闭症的新闻刷到了热搜上,估计很多人看到这则消息,惊讶至极,粪菌移植?把别人的粑粑弄进自己肚子里?听起来就超级重口啊!很多人好奇到底是怎么将健康人的粪菌... 查看详情

聊聊百度搜索背后的故事(代码片段)

聊聊“吴牙签”背后的搜索引擎技术大家好,我是鱼皮,今天分享点有趣的技术知识。前两天,我想上网买包牙签,于是就打开了某度搜索。结果让我懵逼,我搜到的第一条内容竟然不是拿来剔牙的工具,... 查看详情

聊聊cookiesessiontoken背后的故事(代码片段)

摘要:Cookie、Session、Token这三者是不同发展阶段的产物本文分享自华为云社区《Cookie、Session、Token背后的故事》,作者:龙哥手记。1.网站交互体验升级作为网友的我们,每天都会使用浏览器来逛各种网站,来... 查看详情

聊聊cookiesessiontoken背后的故事(代码片段)

摘要:Cookie、Session、Token这三者是不同发展阶段的产物本文分享自华为云社区《Cookie、Session、Token背后的故事》,作者:龙哥手记。1.网站交互体验升级作为网友的我们,每天都会使用浏览器来逛各种网站,来... 查看详情

聊聊cookiesessiontoken背后的故事

△点击上方“Python猫”关注,回复“1”领取电子书大家好,我是猫哥(●—●)。今天和大家聊一下关于cookie、session、token的那些事儿。这是一个读者朋友面试微信的实习岗位时遇到的,在此和大家分享一下。话不多说... 查看详情

你不知道的vscode代码高亮原理(代码片段)

全文5000字,解读vscode背后的代码高亮实现原理,欢迎点赞关注转发。Vscode的代码高亮、代码补齐、错误诊断、跳转定义等语言功能由两种扩展方案协同实现,包括:基于词法分析技术,识别分词token并应用高亮样式基于可编程语... 查看详情

多线程编程?聊聊并发的背后知识(代码片段)

一、现代计算机理论模型与工作方式现代计算机模型是基于-冯诺依曼计算机模型。计算机在运行时,先从内存中取出第一条指令,通过控制器的译码,按指令的要求,从存储器中取出数据进行指定的运算和逻辑操... 查看详情

大白话聊聊微服务——人人都能看懂的演进过程

这篇博客的本意是希望看到这篇文章的读者能够很轻松的理解我想表达的意思。但程序向的分享经常会不经意间就贴上了代码,很可能就会让人看的很懵。而且我认为分享一个东西,只有对方真正明白了其中的逻辑,才是有意义... 查看详情

《你不知道的javascript》系列分享专栏

《你不知道的JavaScript》系列分享专栏你不知道的JavaScript”系列就是要让不求甚解的JavaScript开发者迎难而上,深入语言内部,弄清楚JavaScript每一个零部件的用途《你不知道的JavaScript》已整理成PDF文档,点击可直接下载至本地查... 查看详情

聊聊百度搜索背后的故事(代码片段)

聊聊“吴牙签”背后的搜索引擎技术大家好,我是鱼皮,今天分享点有趣的技术知识。前两天,我想上网买包牙签,于是就打开了某度搜索。结果让我懵逼,我搜到的第一条内容竟然不是拿来剔牙的工具,... 查看详情

《你不知道的javascript[中卷]》14——asynquence附录

 《你不知道的JavaScript[中卷]》【14】——asynquence附录 查看详情

关于单元测试你不知道的那些事

查看详情

前端学习(3324):你不知道javascript说闭包

查看详情

关于单元测试你不知道的那些事

查看详情

关于单元测试你不知道的那些事

查看详情

javascript你不知道的事儿

if(in)语句letnames=['Lily','Barry','Dendi','Boogie','Lily'];letnameNum=names.reduce((pre,cur)=>{if(curinpre){//pre中是否有cur属性pre[cur]++;}else{pre[cur]=1;//为pre这个对象添加cur属性,并且赋值为1}returnpre;},{ 查看详情