在许多应用程序中,我们遇到过需要字节数组构建器的场景,类似于 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);