内存高效且快速的字节数组构建器实现

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 54w+ 字,讲解图 2476+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 1900+ 小伙伴加入学习 ,欢迎点击围观

在许多应用程序中,我们遇到过需要字节数组构建器的场景,类似于 StringBuilder。我们寻求一个选项,我们可以在其中附加字节(数组),并最终获得构造的数组。

由于 Java 不提供任何此类库,因此大多数创建一个至少具有以下行为的简单实用程序。


 byte[] toBytes();
ByteArrayBuilder append(byte[] bytes);

在其最简单的形式(Java 1.6+)中,实现可以如下所示:


 byte[] toBytes();
ByteArrayBuilder append(byte[] bytes);

为简洁起见,未提供完整课程。

此方法是可以实现的多种方法之一。然而,在任何此类解决方案中,都会有多个中间数组实例化(上面的第 4 行)。如果堆内存使用率很高(尽管应该在伊甸园空间),这可能会变得很难看,在循环中创建大字节数组,并导致 OOM 异常。

在运行固定最大堆大小的测试时,我特别面临“超出 GC 开销限制”和“Java 堆空间”错误。

我们可以消除这个中间数组实例化吗?我在这里提供的解决方案正是这样做的。请注意:为了避免中间实例化,我们将使用(著名的)sun.misc.Unsafe 来利用堆外分配。

与之前的解决方案相比,这产生的堆使用量减少了大约 3.5 倍,正如在我的笔记本电脑(Ubuntu 12.04、8gb ram)中使用 Java1.7u79 测试的那样,没有额外的 JVM 参数。性能也稍微好一些(执行时间),但我真的会更多地考虑内存效率。


 byte[] toBytes();
ByteArrayBuilder append(byte[] bytes);