字符串与字节数组,性能

(这篇文章是关于高频类型编程)

我最近在一个论坛上看到(我认为他们正在讨论Java),如果你必须解析很多字符串数据,最好使用字节数组而不是带split()的字符串。 确切的post是:

使用任何语言,C ++,Java,C#的一个性能技巧是避免对象创建。 这不是分配或GC的成本,而是访问不适合CPU缓存的大型内存arrays的成本。

现代CPU比它们的内存快得多。 对于每次缓存未命中,它们会停止许多周期。 大多数CPU转置预算都是通过大缓存和大量滴答来分配的。

GPU通过准备执行大量线程来隐藏内存访问延迟并且几乎没有缓存并将晶体管花费在更多内核上,从而以不同方式解决问题。

因此,例如,不是使用String和split来解析消息,而是使用可以就地更新的字节数组。 您真的希望避免对大型数据结构进行随机内存访问,至少在内部循环中是这样。

他只是说“不要使用字符串,因为它们是一个对象并且创建对象是昂贵的”? 还是他说了别的什么?

使用字节数组是否确保数据尽可能长时间保留在缓存中? 当你使用一个字符串是否太大而无法保存在CPU缓存中? 一般来说,使用原始数据类型是编写更快代码的最佳方法吗?

他说如果你将一个块文本分解成单独的字符串对象,那么这些字符串对象的位置比大文本更糟。 每个字符串及其包含的字符数组将在内存中的其他位置; 它们可以遍布各处。 在处理数据时,内存缓存可能必须进出才能访问各种字符串。 相比之下,一个大型arrays具有最佳可能的位置,因为所有数据都在一个内存区域上,并且高速缓存抖动将保持最小。

当然,这有一些限制:如果文本非常非常大,并且您只需要解析其中的一部分,那么这些少数小字符串可能比大块文本更适合缓存。

使用byte[]char*代替字符串进行HFT还有很多其他原因。 字符串由Java中的16位char组成,并且是不可变的。 byte[]ByteBuffer很容易回收,具有良好的缓存位置,可以脱离堆(直接)保存副本,避免使用字符编码器。 这一切都假设您使用的是ASCII数据。

char*或ByteBuffers也可以映射到网络适配器以保存另一个副本。 (对于ByteBuffers的一些摆弄)

在HFT中,您很少同时处理大量数据。 理想情况下,您希望在插入Socket时立即处理数据。 即一次一个数据包。 (约1.5 KB)