为什么/何时不希望在JVM中启用Java 8 UseStringDeduplication?

Nin*_*tou 25 java optimization performance java-8

Java 8引入了String Deduplication,它可以通过启动JVM来启用,该-XX:+UseStringDeduplication选项允许通过引用类似String对象而不是保留重复来保存一些内存.当然,它的效果因程序而异,具体取决于使用情况,Strings但我认为一般来说它可以被认为对大多数应用程序(如果不是全部)都有益,这让我对以下几点感到好奇:

为什么默认情况下不启用?是因为与去重复相关的成本还是因为G1GC仍然被认为是新的?

是否存在(或可能存在)您不想使用重复数据删除的边缘情况?

Ste*_*n C 27

字符串重复删除可能有害的情况包括:

  • 许多字符串但复制概率非常低:查找重复项的时间开销以及重复数据删除哈希表的时间和空间开销将无法偿还.
  • 重复的合理概率,但大多数字符串在几个GC周期内死亡1:如果重复数据库很快就要进行GC 重复数据删除,则重复数据删除的效益要小得多.

(第二种情况不是关于不能在第一个GC循环中存活的字符串.对于GC甚至尝试对它知道是垃圾的字符串进行重复删除是没有意义的.)

我们只能推测为什么Java团队默认情况下没有打开重复数据删除,但他们处于更好的位置,可以对你和我做出理性(即基于证据的)决策.我的理解是他们可以访问许多大型实际应用程序,用于基准测试/尝试优化的效果.他们也可能与许多合作伙伴或客户组织建立了深入的联系,他们拥有类似的大型代码库和对效率的担忧......他们可以询问有关哪些优化真正起作用的信息.

1 - 这取决于StringDeduplicationAgeThreshold JVM设置的值.默认为3意味着(大致)字符串必须存在3个次要集合或要考虑重复数据删除的主要集合.但无论如何,如果一个字符串被删除然后发现不久之后就无法访问,那么该字符串的重复删除开销将无法偿还.


如果您在考虑何时应该考虑启用重复数据删除,我的建议是尝试一下,看看它是否对每个应用程序有帮助.但是你需要做一些应用程序级的基准测试(这需要付出努力!)以确保重复数据删除是有益的......

仔细阅读JEP 192还可以帮助您理解问题,并判断它们如何应用于您的Java应用程序.


Eug*_*ene 18

我完全明白这不回答这个问题,只是想提一下jdk-9引入了另一个默认启用的优化:

-XX:+ CompactStrings

其中Latin1字符占用一个字节而不是两个(通过char).由于这种变化,String的许多内部方法都发生了变化 - 它们对用户的行为相同,但在内部它们在很多情况下都更快.

同样在Strings通过加号连接两个字符串的情况下,javac将生成不同的字节码.

没有字节码指令将两个字符串连接在一起,因此javac会生成一个

StringBuilder的追加#

在后端.直到jdk-9.

现在字节码委托给了

StringConcatFactory#makeConcatWithConstants

要么

StringConcatFactory#makeConcat

通过invokedynamic字节码指令:

   aload_0
   1: aload_2
   2: aload_1
   3: invokedynamic #8,  0 // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
   8: areturn 
Run Code Online (Sandbox Code Playgroud)

两个字符串如何连接是一个运行时决定.它可能仍然是一个StringBuilder,或者它可能是字节数组等的串联.你知道这可以改变,你将获得最快的解决方案.

编辑

我刚刚调试过,看到有很多关于如何附加这些字符串的策略:

    private enum Strategy {
    /**
     * Bytecode generator, calling into {@link java.lang.StringBuilder}.
     */
    BC_SB,

    /**
     * Bytecode generator, calling into {@link java.lang.StringBuilder};
     * but trying to estimate the required storage.
     */
    BC_SB_SIZED,

    /**
     * Bytecode generator, calling into {@link java.lang.StringBuilder};
     * but computing the required storage exactly.
     */
    BC_SB_SIZED_EXACT,

    /**
     * MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
     * This strategy also tries to estimate the required storage.
     */
    MH_SB_SIZED,

    /**
     * MethodHandle-based generator, that in the end calls into {@link java.lang.StringBuilder}.
     * This strategy also estimate the required storage exactly.
     */
    MH_SB_SIZED_EXACT,

    /**
     * MethodHandle-based generator, that constructs its own byte[] array from
     * the arguments. It computes the required storage exactly.
     */
    MH_INLINE_SIZED_EXACT
}
Run Code Online (Sandbox Code Playgroud)

默认为:

MH_INLINE_SIZED_EXACT