Java 9中的紧凑字符串
Java 9的增强功能之一是紧凑型字符串(Compact String),其目标是使字符串类和相关类在保持大多数情况下的性能的同时,更节省空间。
在Java中引入紧凑型字符串的动机
直到Java 8 String在内部存储为字符数组,每个字符占用2个字节的空间,其中UTF16用于字符编码。
从许多不同的应用程序收集的数据表明,字符串是堆使用的主要组成部分,而且大多数String对象仅包含Latin-1(也称为ISO-8859-1字符)。 Latin-1是8位字符集,表示它需要1个字节的空间,即每个字符比UTF16小1个字节。如果可以使用Latin-1字符编码存储字符串,这将大大减少String对象的内存使用量。这就是Java中紧凑型Strings背后的动机。
Java 9紧凑字符串
从Java 9开始,此空间效率优化功能通过使用称为紧凑字符串的新功能引入了Java中的String类。
代替char数组,Java 9及更高版本的String在内部存储为字节数组和一个encoding-flag字段。
如果可以使用每个1字节存储String的所有字符,则此新的String类将存储编码为ISO-8859-1 / Latin-1(每个字符1个字节)的字符。
如果String的任何字符需要2个字节(在特殊字符的情况下),则String的所有字符都存储为UTF-16(每个字符2个字节)。
如何确定是否必须使用UTF16或者Latin-1字符编码,使用称为编码器的编码标志字段完成。
因此,在Java 8 String类中,该代码用于String存储
/** The value is used for character storage. */ private final char value[];
从Java 9开始更改为使用byte []
@Stable private final byte[] value;
还添加了一个用于标识编码的标志(名为coder的字段),
/** * The identifier of the encoding used to encode the bytes in * {@code value}. The supported values in this implementation are * * LATIN1 * UTF16 * * @implNote This field is trusted by the VM, and is a subject to * constant folding if String instance is constant. Overwriting this * field after construction will cause problems. */ private final byte coder;
可以具有以下两个值之一。
@Native static final byte LATIN1 = 0; @Native static final byte UTF16 = 1;
紧凑型String的String方法的更改
String类中的方法也更改为检查String是存储为Latin-1字符还是UTF-16字符,并使用适当的实现。例如带有紧凑字符串的String类的substring()方法会更改
public String substring(int beginIndex) { if (beginIndex < 0) { throw new StringIndexOutOfBoundsException(beginIndex); } int subLen = length() - beginIndex; if (subLen < 0) { throw new StringIndexOutOfBoundsException(subLen); } if (beginIndex == 0) { return this; } return isLatin1() ? StringLatin1.newString(value, beginIndex, subLen) : StringUTF16.newString(value, beginIndex, subLen); } private boolean isLatin1() { return COMPACT_STRINGS && coder == LATIN1; }
使用XX:-CompactStrings选项
默认情况下,启用"压缩字符串"选项,可以使用-XX:-CompactStrings VM选项禁用该选项。如果应用程序中主要使用UTF-16字符串,则可能要禁用它。