将为a
和分配多少字节b
?
import android.graphics.Bitmap;
Bitmap[][][] a = new Bitmap[1000][2][2];
Bitmap[][][] b = new Bitmap[2][2][1000];
请注意,我只询问纯数组占用的内存,内部没有对象。
我为什么要问?因为我正在写一个安卓游戏。对我来说顺序无所谓,但如果有内存差异,还是省一些就好了。
是的,它确实有所作为。
在 Java 中,2D 数组是 1D 数组的数组,并且数组(像所有对象一样)除了保存元素本身所需的空间外,还具有标题。
所以考虑int[10][2]
vs int[2][10]
,并假设一个 32 位 JVM。
int[2][10]
由一个 2 个元素的数组和 2 个 10 个元素的数组组成。总计 - 3 个数组对象 + 22 个元素。int[10][2]
由一个 10 个元素的数组和 2 个元素的 10 个数组组成。总计 - 11 个数组对象 + 30 个元素。如果我们假设标头大小是 3 个 32 位字(典型的 32 位 JVM)并且引用是 1 个 32 位字,那么
int[2][10]
占用 3*3 + 22*1 = 31 个字 = 124 个字节int[10][2]
占用 11*3 + 30*1 = 63 个字 = 252 个字节应用相同的逻辑,您可以估计具有更多维数的数组的大小。
但很明显,如果最大维度是最右边的维度,则使用的空间更少。
我已经用int
数组完成了数学运算,但是在 32 位机器上 anint
和 areference
占用相同的字节数。在 64 位机器上,引用的大小可以与 aint
或 a相同long
,具体取决于 JVM 选项。标头大小也可能不同......不完全确定......可能取决于平台。
我没有考虑容纳Bitmap
对象本身所需的空间,但是无论您如何组织数组,它都是一样的。
是的,它有所作为。试试这个-Xmx8M
:
// throws OutOfMemoryError
public static void main(String[] args) {
int[][] a = new int[500000][2];
System.out.println("a.length: '" + (a.length) + "'");
}
// works
public static void main(String[] args) {
int[][] a = new int[2][500000];
System.out.println("a.length: '" + (a.length) + "'");
}
第一个会抛出 OutOfMemoryError,第二个会通过。
原因是,第一个版本创建了 500.000 个长度为 2 的数组,而第二个版本创建了 2 个长度为 500.000 的数组。
参考:
在诸如 C 之类的语言中,二维数组(或者实际上是任何多维数组)本质上是一个具有明智指针操作的一维数组。在 Java 中情况并非如此,其中多维数组实际上是一组嵌套数组。这意味着二维数组的每一行都有一个对象的开销,因为它实际上是一个单独的对象!
在热点上尝试时(确切的数字可能与您在 dalvik 上获得的数字不同,但结论应该相似),我得到以下结果:
对象数组(1000x2x2):76034 字节
对象数组(2x2x1000):16137 字节
这符合一个粗略的计算:
[2][2][1000]
Array # Header Size Memory Number Total
1 16 2 24 1 24
2 16 2 24 2 48
3 16 1000 4016 4 16,064
Grand Total 16,136
[1000][2][2]
Array # Header Size Memory Number Total
1 16 1000 4016 1 4,016
2 16 2 24 1000 24,000
3 16 2 24 2000 48,000
Grand Total 76,016
下面的测试代码,运行-XX:-UseTLAB
以获得更准确的结果。
public class TestMemory {
private static final int SIZE = 100;
private static Runnable r;
private static Object o;
private static void test(Runnable r, String name, int numberOfObjects) {
long mem = Runtime.getRuntime().freeMemory();
r.run();
System.out.println(name + ": " + (mem - Runtime.getRuntime().freeMemory()) / numberOfObjects + " bytes");
}
public static void main(String[] args) throws Exception {
r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new Object[1000][2][2];} };
test(r, "Object array (1000x2x2)", SIZE);
r = new Runnable() { public void run() { for (int i = 0; i < SIZE; i++) o = new Object[2][2][1000];} };
test(r, "Object array (2x2x1000)", SIZE);
}
}
没有内存差异,但您的数组索引的顺序 - 理论上 - 可能会影响程序的速度。
您通常在嵌套循环中处理多维数组内容。因此,您的数组应该以您在内部循环中处理相邻元素的方式组织,以允许编译器生成最有效的代码。我不知道 Java 如何组织内存,但认为它与 C/C++ 没有什么不同:
int a[10][100];
for (i = 0; i < 10; ++i) {
for (j = 0; j < 100; ++j) {
do_something_with(a[i][j]);
}
}