如何有效地将 String 序列化为一个已存在的 ByteBuffer?

How to serialize String to an existed ByteBuffer efficiently?

好像String.getBytes()会新建一个字节数组,所以多了一份内存拷贝。我可以在没有中间字节数组的情况下将字符串直接编码为 ByteBuffer 吗?

例如:

void putString(ByteBuffer bb, String s) {
    byte[] arr = s.getBytes(StandardCharsets.UTF_8);
    bb.put(arr);
}

这段代码会创建一个字节数组,将字符串编码到这个字节数组中,然后将字节数组的内容复制到ByteBuffer中。 我觉得字节数组不是必须的,它会带来GC和额外的内存拷贝。

不,这是不可能的。字符串对象没有编码。

字符串对象是不可变的。 class 的整个想法是 而不是 允许操纵任何底层数据结构(主要是出于安全和性能优化的原因)。

从这个意义上讲:在 Java 中没有其他更好的方法来获取构成字符串对象的字节。

您可以使用 CharsetEncoder 直接写入 ByteBuffer:

static void putString(ByteBuffer buffer, String str, Charset charset) {
    CharsetEncoder encoder = charset.newEncoder();
    encoder.encode(CharBuffer.wrap(str), buffer, true);
    encoder.flush(buffer);
}

您有责任确保分配了足够的 space。也可以查看encode()方法的结果,看是否成功。

我想不出一个简单的方法来完全消除中间字节数组。

但是,如果您因为字符串很大而担心这一点,您可以将其分成块:

  for(offset=0; offset<str.length(); offset+=chunkSize) {
      String chunk = str.substring(offset, offset+chunkSize);
      byteBuffer.put(chunk.getBytes(StandardCharsets.UTF_8));
  }

但是,如果您的输入字符串足够大以至于有必要进行此优化,则您程序的整体架构可能设计不当。

您应该担心 GC 性能,除非您在分析时发现异常情况。 JRE 在高效 GC 方面非常出色