小字节数组是指长度从 10 到 30 的字节数组。
存储是指将它们存储在RAM中,而不是序列化和持久化到文件系统。
System macOS 10.12.6, Oracle jdk1.8.0_141 64bit, JVM args -Xmx1g
例子:
new byte[200 * 1024 * 1024]
的预期行为是 ≈200mb 的堆空间
public static final int TARGET_SIZE = 200 * 1024 * 1024;
public static void main(String[] args) throws InterruptedException {
byte[] arr = new byte[TARGET_SIZE];
System.gc();
System.out.println("Array size: " + arr.length);
System.out.println("HeapSize: " + Runtime.getRuntime().totalMemory());
Thread.sleep(60000);
}
但是对于较小的数组,数学并不是那么简单
public static final int TARGET_SIZE = 200 * 1024 * 1024;
public static void main(String[] args) throws InterruptedException {
final int oneArraySize = 20;
final int numberOfArrays = TARGET_SIZE / oneArraySize;
byte[][] arrays = new byte[numberOfArrays][];
for (int i = 0; i < numberOfArrays; i++) {
arrays[i] = new byte[oneArraySize];
}
System.gc();
System.out.println("Arrays size: " + arrays.length);
System.out.println("HeapSize: " + Runtime.getRuntime().totalMemory());
Thread.sleep(60000);
}
甚至更糟
问题是
这些开销从何而来? 如何有效地存储和使用小字节数组(数据 block )?
更新 1
基本数学表示 new byte[1]
权重 24 个字节。
更新 2
根据What is the memory consumption of an object in Java?
Java 中对象的最小大小为 16 字节。从我之前的 "measurements" 24 个字节 -4 个字节用于 int 长度 -1 个实际字节的数据 = 3 个字节的一些 其他垃圾 填充。
最佳答案
好的,所以如果我理解正确(如果不是请询问 - 将尝试回答),这里有几件事。首先是您需要正确的测量工具和JOL是我唯一信任的人。
让我们从简单的开始:
byte[] two = new byte[1];
System.out.println(GraphLayout.parseInstance(one).toFootprint());
这将显示 24 字节
(12
用于 mark
和 class
字词 - 或对象 header + 4 字节padding),1 byte
为实际值,7 bytes 为 padding
(内存为 8 字节对齐)。
考虑到这一点,这应该是一个可预测的输出:
byte[] eight = new byte[8];
System.out.println(GraphLayout.parseInstance(eight).toFootprint()); // 24 bytes
byte[] nine = new byte[9];
System.out.println(GraphLayout.parseInstance(nine).toFootprint()); // 32 bytes
现在让我们转到二维数组:
byte[][] ninenine = new byte[9][9];
System.out.println(GraphLayout.parseInstance(ninenine).toFootprint()); // 344 bytes
System.out.println(ClassLayout.parseInstance(ninenine).toPrintable());
由于java没有true二维数组;每个嵌套数组本身就是一个具有标题和内容的对象 (byte[]
)。因此,单个 byte[9]
具有 32 个字节
(12
header + 4
填充)和 16字节
用于内容(9 字节
用于 实际 内容 + 7 字节
填充)。
ninenine
对象总共有 56
个字节:16
header + 36
用于保存对九个的引用objects + 4 bytes
用于填充。
在此处查看生成的示例:
byte[][] left = new byte[10000][10];
System.out.println(GraphLayout.parseInstance(left).toFootprint()); // 360016 bytes
byte[][] right = new byte[10][10000];
System.out.println(GraphLayout.parseInstance(right).toFootprint()); // 100216 bytes
增加了 260%;因此,只需更改为其他方式,您就可以节省大量空间。
但更深层次的问题是,Java 中的每个对象都有这些 header ,没有 header 对象还没有。它们可能会出现并被称为 Value Types .可能是在实现的时候——原语数组至少不会有这种开销。
关于java - 如何在 Java 中高效地存储小字节数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45829943/