将为a
和b
分配多少字节?
import android.graphics.Bitmap;
Bitmap[][][] a = new Bitmap[1000][2][2];
Bitmap[][][] b = new Bitmap[2][2][1000];
请注意,我只询问纯数组所占用的内存,内部没有任何对象。
我为什么要问?因为我正在写一款Android游戏。对我来说,顺序无关紧要,但如果存在差异,最好保存一些。
答案 0 :(得分:10)
是的确有所作为。
在Java中,2D数组是一维数组的数组,除了保存元素本身所需的空间外,数组(如所有对象)都有标题。
因此,请考虑int[10][2]
与int[2][10]
,并假设为32位JVM。
int[2][10]
由一个包含2个元素的数组和2个包含10个元素的数组组成。总计 - 3个数组对象+22个元素。int[10][2]
由一个包含10个元素的数组和10个包含2个元素的数组组成。总计--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位计算机上,int
和reference
占用相同的字节数。在64位计算机上,引用的大小可以与int
或long
相同,具体取决于JVM选项。标题大小也可能不同....不完全确定......可能依赖于平台。
我没有说明保留Bitmap
个对象本身所需的空间,但是你组织数组是一样的。
答案 1 :(得分:3)
在热点上尝试时(具体数字可能与你在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);
}
}
答案 2 :(得分:3)
是的,它有所作为。只需使用-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中并非如此,其中多维数组实际上是一组嵌套数组。这意味着二维数组的每一行都有一个对象的开销,因为它实际上是一个单独的对象!
答案 3 :(得分:-1)
没有内存差异,但是数组索引的顺序可以 - 理论上 - 对你的程序速度有影响。
您通常在嵌套循环中处理多维数组内容。因此,您的数组应该以一种方式组织,以便在内部循环中寻址相邻元素,以允许编译器生成最有效的代码。我不知道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]);
}
}