跳到主要内容

JEP 254:紧凑字符串

QWen Max 中英对照

概述

采用更节省空间的字符串内部表示形式。

目标

在大多数场景中保持性能并为所有相关的 Java 和本地接口保留完全兼容性的同时,提高 String 类和相关类的空间效率。

非目标

在字符串的内部表示中使用替代编码(如 UTF-8)并不是目标。后续的 JEP 可能会探讨这种方法。

动机

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

描述

我们建议将 String 类的内部表示形式从 UTF-16 的 char 数组更改为 byte 数组加上一个编码标志字段。新的 String 类会根据字符串的内容,将字符存储为 ISO-8859-1/Latin-1(每个字符一个字节)或 UTF-16(每个字符两个字节)的编码格式。编码标志将指示使用的是哪种编码。

诸如 AbstractStringBuilderStringBuilderStringBuffer 等与字符串相关的类将被更新为使用相同的表示形式,HotSpot 虚拟机的内置字符串操作亦是如此。

这完全是一个实现上的变更,现有公共接口没有任何变化。目前没有计划添加任何新的公共 API 或其他接口。

到目前为止完成的原型设计工作证实了内存占用的预期减少、GC 活动的大幅减少,以及在某些极端情况下出现的轻微性能下降。

更多细节请参见:

替代方案

我们在 JDK 6 的更新版本中尝试了一个“压缩字符串”功能,该功能通过一个 -XX 标志启用。启用后,String.value 会被更改为一个 Object 引用,可能指向一个 byte 数组(对于仅包含 7 位 US-ASCII 字符的字符串),或者是一个 char 数组。这个实现并未开源,因此难以维护,并且很难与主分支的 JDK 源代码保持同步。此功能后来已被移除。

测试

对平台如此基础的部分进行更改,全面的兼容性和回归测试将是至关重要的。

我们还需要确认已经实现了该项目的性能目标。必须对内存节省情况进行分析。应该使用广泛的工作负载进行性能测试,范围从专注的微基准测试到大规模服务器工作负载不等。

我们将鼓励整个 Java 社区通过这项变更进行早期测试,以便找出任何剩余的问题。

风险与假设

优化字符存储以节省内存可能会在运行时性能方面带来权衡。我们预计这将通过减少 GC(垃圾回收)活动来抵消,并且我们将能够保持典型服务器基准测试的吞吐量。如果无法做到这一点,我们将研究优化措施,以便在内存节省和运行时性能之间取得可接受的平衡。

其他近期的项目已经减少了字符串所使用的堆空间,特别是 JEP 192:G1 中的字符串去重。即使在消除重复之后,如果采用更高效的编码方式,剩余的字符串数据仍可占用更少的空间。我们假设该项目仍将带来与所需投入相符的收益。