【问题标题】:Why is getting a value from a variable preferred than getting it from an array?为什么从变量中获取值比从数组中获取值更受欢迎?
【发布时间】:2015-07-08 17:40:51
【问题描述】:

考虑以下程序:

int []array = {10, 20, 30, 40, 50};
int x = array[0];
for(int i = 0; i < array.length; i++)
{
 System.out.println(x * array[i]);
 System.out.println(array[0] * array[i]);
}

当一个数组被声明时,它被存储在一起驻留的内存中。

array:     [0]    [1]    [2]    [3]   [4]
Value:     10     20     30     40    50
Location:  100   102     104    106   108

现在当 x 被赋值为 array(10) 的第一个元素时。

x 在内存中存储了一个值为10 的值。

variable :  x
Value :     10
Location :  120

现在当我们调用 for 循环时,

第一个打印语句将引用位置120 的值并说我有一个值10。

第二个打印语句还将引用位置100,并说它有一个值10。

当两个语句每次都必须寻找内存位置时,为什么第一个语句会更优化?

编辑 如果x被多次使用,在同一个程序中。

int []array = {10, 20, 30, 40, 50};
int x = array[0];
for(int i = 0; i < array.length; i++)
{
 System.out.println(x * array[i] + (x + 1) * array[i] - ( x + 2));
 System.out.println(array[0] * array[i] + (array[0] + 1) * array[i] - (array[0] + 2));
}

这里 x 被多次使用。所以人们更喜欢使用x,而不是每次都调用array[0]。

不过,两者都必须查。

【问题讨论】:

  • 如果你有一个愚蠢的编译器,我想你可以消除重复的内存访问。
  • 如果我们谈论的是未优化的编译,Java会在每个索引处检查数组索引的范围。
  • 不是优化偏好,它们的复杂度是一样的~,就是遵守DRY原则。 en.wikipedia.org/wiki/Don't_repeat_yourself
  • 因为我们不直接访问数组,首先 jvm 正在搜索数组的引用,然后创建位于不同位置(主要在堆中)的数组对象。但是局部变量驻留在堆栈中。所以显然变量会更有效。@UmaKanth
  • 这个问题没有通过97/3 rule:不感兴趣。

标签: java arrays variables optimization


【解决方案1】:

访问array[i] 时,处理器必须查找array 的内存地址,然后将i 添加到该地址以获取您请求的变量。

访问x时,处理器可以直接从x获取变量。

在 Java 中,只有原语存储在堆栈中,因此 array 将是指向堆中某物的指针,而 x 将存储在堆栈中。这仅适用于 x 是一个原语的情况。如果array 包含对象(因此x 是指向对象的指针),则两者都将存储在堆中。

所以主要区别在于访问array[i]时您将访问location-of-array-plus-i,但访问x时您将访问 x 的位置。值得注意的是,array[0](或任何其他固定索引)通常可以优化为一条指令。

现在,你应该担心这个吗?不,绝对不是。这两种方式之间甚至不太可能存在可测量的性能差异,即使性能差异极不可能影响您 - 您的应用程序可能会做更多耗时的工作,而不仅仅是访问内存中的变量。编译器也很可能会对此进行优化,以减少所需的内存查找次数,并且处理器缓存也将发挥作用。

最好这样写的真正原因:

int x = array[0]
int y = array[1]
int result = x + y + x * y + x * (x - y)

它是否比以下更具可读性:

int result = array[0] + array[1] + array[0] * array[1] + array[0] * (array[0] - array[1])

【讨论】:

  • 我完全同意你的回答。也许您还可以提到加载 from 和 address 加上一个固定的偏移量通常可以编译成一条指令。并且编译器无论如何都可以自己进行这些转换。
猜你喜欢
  • 2019-09-09
  • 1970-01-01
  • 2019-06-11
  • 1970-01-01
  • 2020-10-25
  • 2021-10-18
  • 1970-01-01
  • 1970-01-01
  • 2012-11-16
相关资源
最近更新 更多