Java 9中的紧凑字符串

时间:2020-01-09 10:34:53  来源:igfitidea点击:

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字符串,则可能要禁用它。