什么是重复字符串?
首先,让我们了解重复字符串的含义。看下面的代码片段:
string1
和 string2
。它们具有相同的内容,即“Hello World”,但它们存储在两个不同的对象中。当你这样做时 string1.equals(string2)
,它将返回“true”,但 string1 == string2
也会返回“false”。这就是我们所说的重复字符串。
为什么有这么多重复字符串?
应用程序最终出现大量重复字符串的原因有多种。在本节中,我们回顾一下两种最常见的模式:
# 1.开发人员为每个请求创建新的字符串对象,而不是引用/重用“公共静态最终字符串文字”。下面的示例可以使用字符串文字模式进行最佳编写
同样,您的应用程序可能会多次从数据库中读取多列(客户名称、地址、州、国家、帐号、ID……)。其中可能存在重复项。您的应用程序通过外部应用程序读取和写入 XML/JSON,并且操作大量字符串。所有这些操作都可以而且经常会创建重复的字符串。
这个问题自诞生以来(早在 20 世纪 90 年代中期)就被 JDK 团队认识到了,因此迄今为止他们已经提出了多种解决方案。此解决方案列表中的最新添加内容是“- XX:+UseStringDeduplication
”。
-XX:+使用字符串重复数据删除
消除重复字符串的最简单方法是传递 -XX:+UseStringDeduplication
JVM 参数。当您在应用程序启动期间传递此 JVM 参数时,JVM 将尝试消除重复的字符串,作为垃圾收集过程的一部分。在垃圾收集过程中,JVM 会检查内存中的所有对象,因此作为该过程的一部分,它会尝试识别其中的重复字符串并尝试将其消除。
这是否意味着如果您只传递 '-XX:+UseStringDeduplication' JVM 参数,您就能立即节省 13.5% 的内存?听起来很简单,对吧?我们希望事情就是这么简单。但这个解决方案有一些问题 -XX:+UseStringDeduplication
。让我们来讨论一下它们。
(1). 仅适用于 G1 GC 算法
有多种垃圾收集算法(串行、并行、CMS、G1……)。 -XX:+UseStringDeduplication
仅当您使用 G1 GC 算法时才有效。因此,如果您正在使用其他GC算法,则需要切换到G1 GC算法才能使用 -XX:+UseStringDeduplication
。
(2)。仅适用于长寿命对象
-XX:+UseStringDeduplication
消除重复的字符串。其寿命较长。它们不会消除短期字符串对象中的重复字符串。如果对象是短暂的,它们很快就会消亡,那么花费资源来消除它们之间的重复字符串又有什么意义呢?这是对一个主要 Java Web 应用程序进行的真实案例研究-XX:+UseStringDeduplication
,该应用程序在 使用时没有显示任何内存释放情况 。但是, -XX:+UseStringDeduplication
如果您的应用程序有大量缓存(因为缓存对象通常是长期存在的对象),则它可能很有价值。
(3)。-XX:字符串重复数据删除年龄阈值
默认情况下,如果字符串在 3 次 GC 运行中幸存下来,就可以进行重复数据删除。可以通过传递这个来改变它 -XX:StringDeduplicationAgeThreshold
由于字符串重复数据删除是在垃圾回收期间执行的,因此可能会影响 GC 暂停时间。然而,假设足够高的重复数据删除成功率将平衡大部分或全部这种影响,因为重复数据删除可以减少 GC 暂停的其他阶段所需的工作量(例如减少要撤离的对象数量)以及减少 GC 频率(由于堆上的压力减少)。要分析GC暂停时间的影响,您可以考虑使用GCeasy等工具