Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java多维数组:内存地址和遍历速度_Java_Arrays_Memory - Fatal编程技术网

Java多维数组:内存地址和遍历速度

Java多维数组:内存地址和遍历速度,java,arrays,memory,Java,Arrays,Memory,我知道在Java中处理二维数组时,访问循环中数组元素的顺序会影响遍历数组所需的时间: int size = 500; int[][] array = new int[size][size]; // Slower for (int i = 0; i < size; i++) { for (int j = 0; j < size; j++) { array[j][i] = 1; } } // Faster for (int i = 0; i <

我知道在Java中处理二维数组时,访问循环中数组元素的顺序会影响遍历数组所需的时间:

int size = 500;
int[][] array = new int[size][size];

// Slower
for (int i = 0; i < size; i++) {
    for (int j = 0; j < size; j++) {
        array[j][i] = 1;
    }
}

// Faster
for (int i = 0; i < size; i++) {
    for (int j = 0; j < size; j++) {
        array[i][j] = 1;
    }
}
在大多数代码运行中,
[i][j][k]
[j][i][k]
的结果是可互换的。为什么会这样

另外,您能解释一下多维数组是如何存储在Java中的吗

给定数组
int[][]array=new int[2][2][2]
,内存地址会是这样的吗(我的理解是,每个块之间可能有其他变量的附加数据,但我已经记录了这些情况,因为它们不相关):
(抱歉,如果图像是混乱的,我只有油漆,并尽力表达我的最佳布局。所以<代码>数组[0 ] [ 0 ] [ [ i] [j] [k] < /代码>将在地址<代码> 06 /代码>

< p>第一个要考虑的是java,仔细地看,没有多维数组,因为它是一个单一的实体。相反,java只处理一维数组,但元素类型本身可以是数组类型,并且语言/编译器支持与C相同的语法,例如,多维度快捷寻址元素

例如,
int[]twoDim=newint[50][100]实际在内存中创建51个对象;一个类型为
int[][]
的数组,其中包含50个类型为
int[]
的元素,并使用类型为
int[100]
的数组填充这50个空间(生成剩余的50个对象)。这51个对象中的每一个都是独立的,它们可以位于堆中的任何位置。实际上,它们甚至不需要在同一个语句中创建

以下两种方法给出了相同的数组作为结果,但第二种方法应该清楚地说明引擎盖下到底发生了什么:

变量B和C的内存布局将不同,因为它们的分配顺序不同。但不要假设它们的内存布局是常量,垃圾收集器可能会在堆中移动它们

如果您担心访问速度,那么迭代数组的最快方法总是最左边的维度到最外面的循环,最右边的维度到最里面的循环(这是严格围绕单个维度在内存中线性定位这一事实构建的)。线性内存访问比随机访问的CPU速度更快(我不想在这里解释原因)

在处理阵列时,可以考虑两种微观优化

首先是尺寸的顺序,当您可以随意订购尺寸时,请将最小的最左边和最大的最右边放置:

第二个变量还节省了大量内存,因为慢变量包含10000 x int[2]=10001个对象,而快变量包含2 x int[10000]=3个对象

第二种是处理数组维度的切片(这是代码不变移动的一种形式):

长和=0;
int[]fastary=newint[2][10000];

对于(inti=0;我是如何测量的?在Java中精确地测量这些东西的性能(甚至精确到“A比B好”)是非常非常困难的。我使用了
System.nanoTime()
在每次循环之前和之后减去差异是的,不,这不会得到准确的结果。如果你想得到测量结果,可以使用JMH或卡尺,实际上可以告诉你A快/慢/等于B。数组的java实现的技术术语是锯齿数组。谢谢你的解释。我不想问理解存储数组数组数组背后的思想……就字节码而言,没有什么能阻止人们使用单个连续内存块来定义n维数组,从而获得更可预测的性能。@edTarik阻止你将多维数组定义为连续bl的东西内存块是java语言规范本身,特别是每个数组(也是)一个对象。通过createArrayB()示例执行步骤(实际上或更好的是在调试器中),并查看整个方法中的数组内容。此外,您可能希望检查术语“锯齿数组”(此功能也是阵列阵列组织的结果)。通过使用索引,您可以很容易地使用一维数组获得与2D数组等效的数组。C内部就是这样做的。因此,JVM中没有任何东西阻止向Java编程语言添加语法糖,以处理2D数组和更传统的锯齿数组。@edTarik我明白您的意思,但这仍然是正确的需要在语言级别上进行更改,而不仅仅是在虚拟机级别。仅使用(纯)语法sugar可以实现的功能是有限的(请看我的上一个代码示例,其中代码不变的移动说明了原因,这将是一个非常基本的添加)。您仍然可以通过自己进行索引数学(使用当前的java语言元素)来模拟经典的C多维数组,而实际上是将数据存储在一个一维数组中,如果你觉得这样做值得付出努力的话。我看了代码不变的代码。我仍然不太明白是什么阻止了使用添加Java语法构造来做到这一点:使用一维数组并使用未更改的JVM进行索引数学。
Time:  12356332 nanoseconds. ([i][j][k])
Time:  18278948 nanoseconds. ([i][k][j])
Time:  13985288 nanoseconds. ([j][i][k])
Time: 126192723 nanoseconds. ([j][k][i])
Time:  39441820 nanoseconds. ([k][i][j])
Time: 156352618 nanoseconds. ([k][j][i])
 public int[][] createArrayA(int n, int m) {
     return new int[n][m];
 }

 public int[][] createArrayB(int n, int m) {
     int[][] array = new int[n][];
     for (int i=0; i<n; ++i)
         array[i] = new int[m];
     return array;
 }
 public int[][] createArrayC(int n, int m) {
     int[][] array = new int[n][];
     for (int i=n-1; i>=0; --i)
         array[i] = new int[m];
     return array;
 }
int[][] slowArray = new int[10000][2];
int[][] fastArray = new int[2][10000];
long sum = 0;
int[][] fastArray = new int[2][10000];
for (int i=0; i<fastArray.length; ++i) {
    int[] subArray = fastArray[i];
    for (int j=0; j<subArray.length; ++j) {
        sum += subArray[j];
    }
}