5

我继承了一段代码,它大量使用 String -> byte[] 转换,反之亦然,用于一些自制的序列化代码。本质上,Java 对象知道如何将它们的组成部分转换为字符串,然后再转换为字节 []。然后,所述字节数组通过 JNI 传递到 C++ 代码中,该代码将 byte[] 重构为 C++ std::strings 并使用这些代码引导反映 Java 对象的 C++ 对象。还有更多内容,但这是这段代码如何工作的高级视图;通信在两个方向上都是这样工作的,因此 C++ -> Java 转换是我上面提到的 Java -> C++ 转换的镜像。

这段代码的一部分——将 String 实际转换为 byte[]——出乎意料地在分析器中显示为消耗大量 CPU。当然,有很多数据正在传输,但这是一个意想不到的瓶颈。

代码的基本大纲如下:

public void convertToByteArray(String convert_me, ByteArrayOutputStream stream)
{
  stream.write(convert_me.getBytes());
}

该功能还有一点点,但不多。上面的函数会为每个 String/Stringified 对象调用一次,并且在将所有成分写入 ByteArrayOutputStream 之后,ByteArrayOutputStream 会转换为 byte[]。通过提取调用将上述内容分解为对分析器更友好的版本convert_me.getBytes()表明,此函数中超过 90% 的时间都花在了 getBytes() 调用中。

有没有办法提高 getBytes() 调用的性能,或者是否有另一种可能更快的方法来实现相同的转换?

正在转换的对象数量非常大。在仅使用一小部分生产数据的分析运行中,我看到对上述转换函数的调用超过 1000 万次。

由于我们非常接近将项目发布到生产环境中,因此目前无法采用一些解决方法:

  • 重写序列化接口,只在 JNI 层传递字符串对象。这是改善情况的明显(对我而言)方法,但它需要对序列化层进行重大重新设计。鉴于我们将在本周早些时候进入 UAT,现在进行这种复杂的更改为时已晚。这是我下一个版本的首要任务,所以它会完成;然而,在那之前我确实需要一个解决方法,但到目前为止代码正在运行,已经使用了多年并且大部分问题都解决了。好吧,除了表演。
  • 更改 JVM(当前为 1.5)也不是一种选择。不幸的是,这是安装在客户端机器上的默认 JVM,很遗憾无法更新到 1.6(在这种情况下可能会更快,也可能不会更快)。任何在大型组织工作过的人都可能明白为什么...
  • 除此之外,我们已经遇到了内存限制,因此尝试缓存至少较大的字符串及其字节数组表示,虽然是一个潜在的优雅解决方案,但可能会导致比它解决的问题更多的问题
4

4 回答 4

4

我猜问题的一部分可能是Java字符串是UTF-16格式——即每个字符两个字节;做getBytes()一堆工作将每个 UTF-16 元素转换为一个或两个字节,这取决于您当前的字符集。

您是否尝试过使用CharsetEncoder - 这应该可以让您更好地控制字符串编码,并允许您跳过默认getBytes实现中的一些开销。

或者,您是否尝试过将字符集明确指定为getBytes,并使用US-ASCII作为字符集?

于 2009-06-21T11:36:00.927 回答
2

我看到几个选项:

  • 如果你有 Latin-1 字符串,你可以只拆分字符串中字符的高字节(我认为 Charset 也这样做)
  • 如果您有更多内核,您还可以在多个内核之间拆分工作(fork-join 框架曾经向后移植到 1.5)
  • 您还可以将数据构建到字符串构建器中,最后只将其转换为字节数组一次。
  • 查看您的 GC/内存使用情况。由于频繁的 GC 中断,过多的内存使用可能会减慢您的算法速度
  • 于 2009-06-21T19:19:30.550 回答
    1

    如果它是您一直转换的相同字符串,您可以将结果缓存在 WeakHashMap 中。

    另外,请查看 getBytes() 方法(如果您安装了 SDK,则可以使用源代码)以了解它的具体作用。

    于 2009-06-21T14:35:39.457 回答
    1

    问题是,即使在今天,Java 中的所有方法都使用 UTF-8 产生式分配内存。要获得编码性能,您需要编写自定义代码并重用 byte[] 缓冲区。Colfer 可以生成代码或只是简单地复制其实现。

    https://github.com/pascaldekloe/colfer/blob/4c6f022c5183c0aebb8bc73e8137f976d31b1083/java/gen/O.java#L414

    于 2017-04-08T22:04:21.683 回答