【问题标题】:String representation in Java and compacting StringsJava 中的字符串表示和压缩字符串
【发布时间】:2016-01-10 07:22:23
【问题描述】:

最近我偶然发现了这个JEP 254: Compact Strings,它主要针对:

总结:对字符串采用更节省空间的内部表示。

根据我目前的经验,Stringschar[] 占据了总堆消耗的很大比例。就像 JIRA 已经指出的那样:

String 类的当前实现将字符存储在 char 数组中,每个字符使用两个字节(16 位)。从许多不同应用程序收集的数据表明,字符串是堆使用的主要组成部分,此外,大多数 String 对象仅包含 Latin-1 字符。此类字符仅需要一个字节的存储空间,因此此类 String 对象的内部 char 数组中有一半空间未使用。

考虑到这一点,我有以下问题:

  • String 只存储需要 1 个字节的字符并且构成堆配置文件的很大一部分时,其他开发人员当前如何处理此问题?
  • 为什么现在正在实施,而之前没有尝试过解决这个问题?
  • 是否已经有旨在解决此问题的开源库?

我已经回答了诸如thisthis 之类的基本问题,这些问题涉及String 的相关事实,其中包括StringPool 和实习String 的工作原理以及为什么String 中的单个字符目前占用2 bytes

【问题讨论】:

  • 你能澄清一下“只有 UTF-8 字符”是什么意思吗?
  • 我的意思是只需要一个字节来存储的字符。
  • 我明白了。发明自己的术语总是很酷。您可能会在其他部分提到您的帖子中提到的 ASCII(基本上是 Unicode 的 0-127 范围)或 Latin-1 - 考虑是否有必要提出您自己的术语。
  • @AlexeiLevenkov 编辑了问题。

标签: java string


【解决方案1】:

这实际上是早些时候尝试过的:在 Java-6 中,有一个选项 -XX:+UseCompressedStrings 启用了类似于 JEP 254 的功能。但是,由于额外的复杂性,这个功能在 Java-7 中被删除了(它引入了像 this 这样的错误或this) 和性能损失。问题之一是这些时间字符串能够共享底层缓冲区(substring() 返回一个与原始字符串共享相同缓冲区的新字符串)。这增加了字符串压缩的复杂性(如果原始字符串使用非Latin1 符号而子字符串仅使用Latin-1 怎么办?)。

现在字符串缓冲区永远不会在不相等的字符串之间共享,因此实现变得更加容易。然而,这非常困难,并且涉及许多警告。 JEP 254 的目标之一是非常努力地尝试,以免失去一点点性能。不要忘记String 类是非常基本的:它的一些方法(如equalsindexOf)是由JIT 编译器内置的;一些场景是特殊处理的(比如优化字符串连接)。所有这些功能都严重依赖于内部字符串表示,也应该为紧凑字符串重写。

如果你想压缩你当前的代码,你可以实现自定义CompactString,它实现了CharSequence接口并在内部使用byte[]。问题是大量现有代码适用于String,而不是CharSequence,而CharSequence 接口实际上非常有限。所以要广泛使用这样的类是相当困难的。

【讨论】:

    【解决方案2】:

    UTF-8 是一种适用于所有 Unicode 字符的字符编码,而 Java 字符串则以 UTF-16 编码存储,并且它们总是这样做。实现可变字符串存储可能会对性能造成巨大影响,因为 JVM 必须首先决定它是查看 Latin-1 字符串值还是 UTF-16 字符串值。

    此外,UTF16 编码提供了对字符串属性和操作的更一致的处理。 Latin-1 字符串必须先转换为 UTF-16 才能附加非拉丁 1 字符。此外,将 Latin-1 字符串与 UTF-16 字符串进行比较是一件很麻烦的事情。基本上,对于几乎所有操作,您都必须将 Latin-1 字符串转换为 UTF-16 字符串(或至少通过 CharSequence 接口对其进行迭代)。

    【讨论】:

      【解决方案3】:

      char(因此是String)在 Java 中的内存表示/编码是 UTF-16,每个 any 字符需要(至少)2 个字节。即使您在程序中使用的字符和编码在其他字符集中需要一个字节(Latin-1UTF-8 的一部分等)。

      这个问题之前可能不是最相关的,但现在有了数 GB 的堆,谁知道还有什么其他原因让他们重新审视精简 JVM 堆签名。

      因为这是一个 JVM 内部问题,所以没有库可以影响它。您需要一个可能不符合规则的自定义 JVM(假设在某处指定了 UTF-16 编码)。

      【讨论】:

      • 我已经知道这一事实,并在问题中也提到了这一点。最后两个不是问题,而是我已经知道的内容。
      • 那么您的How is this handled currently 问题应该是什么意思?
      • 我的意思是其他开发人员如何解决这个问题?编辑只是为了清楚是否其他人感到困惑
      • 没有什么可以克服的。如果您的字符串没有足够的内存,请购买更多内存。
      • 不能用字节数组来解决这个问题吗?但后来我们总是把它转换成字符串,所以不确定。
      猜你喜欢
      • 1970-01-01
      • 2012-05-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-13
      • 1970-01-01
      • 1970-01-01
      • 2019-10-15
      相关资源
      最近更新 更多