Java缓冲区类型与原生数组:哪个更快?

04/07 09:08
阅读数 22

使用 C 语言开发时,必须手动分配和释放内存,这是一个容易出错的过程。相反,像 Java 这样的之后的一些语言通常会自动管理内存。Java 依赖于垃圾回收。实际上,内存是根据需要来分配,然后 Java 发现哪些数据不再访问,并回收相应的内存。垃圾回收过程既快速又安全,但是它不是免费的:尽管进行了数十年的优化,但它仍然可能给开发人员带来一些麻烦。



Java 具有原生数组(例如 int[] 类型),这些数组通常在 Java 堆上分配。也就是说,它们由 Java 作为动态数据进行分配和管理,并进行垃圾回收。


Java 还具有 Buffer 类型,如 IntBuffer,它是一种高级抽象,可以由原生 Java 数组实现,也可以由其他数据源(包括 Java 堆外数据)来实现。因此,可以使用 Buffer 类型来避免过多地依赖 Java 堆。


与原生数组相比,Buffer 会存在一定性能损失。我不是说 Buffer 慢。事实上,如果在 Buffer 和流(DataInputStream)之间做一个选择,你应该更倾向于 Buffer 类型。然而,根据我的经验,Buffer 在性能方面不如原生数组。


我可以用 new int[50000] 或 IntBuffer.allocate(50000) 来创建一个包含 50,000 个整数的数组。后者本质上应该是创建一个数组(在 Java 堆上),然后用 IntBuffer 接口来包装。


一个可能的直觉是,用高级接口包装一个数组应该是免费的。虽然高层次的抽象确实可以不带来性能上的损失(有时甚至可以带来性能上的提升),但是否会带来性能上的提升是一个经验问题。你绝对不应该只是假设你的抽象是免费得来的。


因为我在做一个经验陈述,但我可以用最简单的测试来证明它,比如给数组 以及 IntBuffer 中的每个元素加 1。


for(int k = 0; k  < s.array.length; k++) {     s.array[k] += 1;}


for(int k = 0; k  < s.buffer.limit(); k++) {     s.buffer.put(k, s.buffer.get(k) + 1);}


我在台式机(OpenJDK 14,4.2 GHz Intel 处理器)上得到结果如下:


也就是说,在此测试中,数组比 IntBuffers 快 4 倍以上。


如果有兴趣,你也可以自己运行以下基准测试。


https://github.com/lemire/Code-used-on-Daniel-Lemire-s-blog/tree/master/2020/11/30


我的看法是,Java 针对数组的许多优化不适用于 Buffer 类型。


当然,我们无法得知 Buffer 从 Java 堆外映射时发生了什么,根据我的经验,情况可能很糟。


Buffer 类型并不会让原生数组过时,至少在性能方面。


英文原文(包含一些精彩评论):

https://lemire.me/blog/2020/11/30/java-buffer-types-versus-native-arrays-which-is-faster/

本文分享自微信公众号 - 业余草(yyucao)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
打赏
0
0 收藏
分享
加载中
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部