Java中的字符串表示和压缩字符串

时间:2016-01-10 07:22:24

标签: java string

最近我偶然发现了JEP 254: Compact Strings基本上针对的目标:

  

摘要:为字符串采用更节省空间的内部表示。

根据我目前的经验,Stringschar[]占据了总消耗量的很大一部分。就像JIRA已经说过:

  

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

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

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

我已经完成了thisthis等关于String的事实的基本问题,其中涵盖了StringPool和实习String如何运作以及为什么单个字符在字符串当前占用2 bytes

3 个答案:

答案 0 :(得分:3)

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

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

如果要对当前代码进行压缩,可以实现自定义CompactString,它实现CharSequence接口并在内部使用byte[]。问题是大量现有代码与String一起使用,而不是CharSequenceCharSequence接口实际上非常有限。因此,广泛使用这类课程将非常困难。

答案 1 :(得分:1)

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

此外,UTF16编码可以更加一致地处理字符串属性和操作。必须首先将Latin-1字符串转换为UTF-16以附加非Latin-1字符。此外,将Latin-1字符串与UTF-16字符串进行比较是一件非常混乱的事情。基本上你必须将Latin-1字符串转换为UTF-16字符串(或者至少通过CharSequence接口迭代它)几乎所有操作。

答案 2 :(得分:-1)

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

这个问题可能在之前并不是最相关的,但是现在有了几千兆字节的堆,谁知道他们在减少JVM堆签名方面有了新的面貌。

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