Java 8 String重复数据删除与String.intern()

Hil*_*kus 18 java string jvm-hotspot deduplication

我正在阅读关于字符串重复数据删除的Java 8更新20中的功能(更多信息),但我不确定这是否基本上String.intern()已经过时了.

我知道这个JVM功能需要G1垃圾收集器,这对许多人来说可能不是一个选项,但假设一个人正在使用G1GC,那么JVM自动重复数据删除与手动拥有intern你的字符串有什么区别/优势/劣势(一个明显的优点是不必通过调用来污染您的代码intern())?

考虑到Oracle可能使G1GC成为java 9中的默认GC,这一点尤为有趣

Zho*_*gYu 10

使用此功能,如果您有1000个不同的String对象,所有对象都具有相同的内容"abc",JVM可以使它们在char[]内部共享相同的内容.但是,您仍然有1000个不同的String对象.

有了intern(),你将只有一个String对象.因此,如果您关注内存节省,intern()那就更好了.它将节省空间,以及GC时间.

但是,intern()上次我听说,表现并不是那么好.拥有自己的字符串缓存可能会更好,即使使用ConcurrentHashMap...但您需要对其进行基准测试以确保.

  • 实际上,String.intern的性能与手动字符串池相当.Mikhail Vorontsov做了一些性能基准测试,结果表明,StringTableSize参数设置得足够高,可以说自己的性能与手动字符串池相当.[http://java-performance.info/string-intern-in-java-6-7-8/](http://java-performance.info/string-intern-in-java-6-7-8 /) (4认同)

Luk*_*ood 6

作为评论参考,请参阅:http : //java-performance.info/string-intern-in-java-6-7-8/。这是非常有见地的参考,我学到了很多东西,但是我不确定它的结论是否一定是“一刀切”。每个方面都取决于您自己的应用程序的需求 - 强烈建议对实际输入数据进行测量!

主要因素可能取决于您控制的内容:

  • 您是否可以完全控制 GC 的选择?例如,在 GUI 应用程序中,仍然有充分的理由使用串行 GC。(该进程的总内存占用要低得多——对于中等复杂的应用程序来说,想想 400 MB 对 ~1 GB,并且更愿意释放内存,例如在使用量出现短暂峰值之后)。因此,您可以选择该选项或为您的用户提供选项。(如果堆仍然很小,暂停应该不是什么大问题)。

  • 您是否可以完全控制代码?G1GC 选项非常适合您无法编辑的 3rd 方库(和应用程序!)。

第二个考虑因素(根据@ZhongYu 的回答)是String.intern可以对String对象本身进行重复数据删除,而 G1GC 必然只能对其私有char[]字段进行重复数据删除。

第三个考虑因素可能是 CPU 使用率,比如您的用户是否关心对笔记本电脑电池寿命的影响。G1GC 将运行一个额外的线程,专门用于对堆进行重复数据删除。例如,我用它来运行 Eclipse 并发现它在启动后导致 CPU 活动的初始阶段增加(想想 1 - 2 分钟),但它解决了一个较小的“使用中”堆并且没有明显的(只是眼睛-球任务管理器) CPU 开销或此后变慢。所以我想一定百分比的 CPU 核心将用于重复数据删除(期间?之后?)高内存流失期间。(当然,如果你在任何地方调用 String.intern 可能会有类似的开销,它也可以串行运行,但是……)

您可能不需要到处都进行字符串重复数据删除。可能只有某些代码区域:

  • 真正影响长期堆使用,并且
  • 创建高比例的重复字符串

通过String.intern有选择地使用,代码的其他部分(可能会创建临时或半临时字符串)不会付出代价。

最后,Guava 实用程序的快速插件:Interner,它:

String.intern()为其他不可变类型提供等效的行为

您也可以将其用于字符串。内存可能是(并且应该是)您最关心的性能问题,因此这可能并不经常适用:但是,当您需要从某个热点区域挤出每一滴速度时,我的经验是基于 Java 的弱引用String.intern()即使在调整了 jvm 选项之后,HashMap 解决方案的运行速度确实比 JVM 的 C++ 实现略快,但始终比。(还有一个好处:您不需要调整 JVM 选项来扩展到不同的输入。)