Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/305.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/12.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 调用array.length的成本是多少_Java_Arrays_Premature Optimization - Fatal编程技术网

Java 调用array.length的成本是多少

Java 调用array.length的成本是多少,java,arrays,premature-optimization,Java,Arrays,Premature Optimization,在应用程序中将for循环更新为for each循环时,我遇到了很多这样的“模式”: for(int i=0,n=a.length;i

在应用程序中将for循环更新为for each循环时,我遇到了很多这样的“模式”:

for(int i=0,n=a.length;i
而不是

for (int i = 0; i < a.length; i++) {
    ...
}
for(int i=0;i
我可以看出,由于不需要在每个循环中调用size()方法,所以可以提高集合的性能。但是使用数组


于是问题出现了:
array.length
是否比常规变量更昂贵?

将其存储在变量中可能会稍微快一点。但如果一个剖析者指出这是一个问题,我会非常惊讶


在字节码级别,使用
arraylength
字节码获取数组的长度。我不知道它是否比一个
iload
字节码慢,但应该没有足够的差异来注意。

不,调用
array.length
O(1)
或常量时间操作

由于
.length
数组
公共
最终
成员,因此它的访问速度并不比局部变量慢。(这与调用像
size()
这样的方法非常不同)

现代JIT编译器可能会立即优化对
.length
的调用

您可以通过查看OpenJDK中JIT编译器的源代码,或者让JVM转储JIT编译的本机代码并检查代码来确认这一点

请注意,在某些情况下,JIT编译器可能无法做到这一点;e、 g

  • 如果正在调试封闭方法,或
  • 如果循环体有足够的局部变量来强制寄存器溢出

  • 我怀疑是否有任何显著的差异,即使有,我敢打赌它可能在编译过程中被优化了。当你试图对这样的事情进行微优化时,你是在浪费时间。首先使代码可读且正确,然后如果出现性能问题,请使用探查器,然后担心选择更好的数据结构/算法(如果合适),然后担心优化探查器突出显示的部分。

    数组的长度存储为数组的成员变量(与元素不同)在java中,获取长度是一个固定的时间操作,就像从一个普通类中读取一个成员变量一样。许多像C和C++这样的老语言不把长度存储为数组的一部分,所以你想在循环开始之前存储长度。你不必在java中这样做。

    < p>这个答案是从C的观点来看的,但是我认为Java也是如此

    C#中的成语

    for (int i = 0; i < a.length; i++) {    ...}
    
    for(inti=0;i
    被识别为在数组上迭代,因此在循环中访问数组时避免了边界检查,而不是每次访问数组时

    这可能通过以下代码识别,也可能无法识别:

    for (int i = 0, n = a.length; i < n; i++) {    ...}
    
    for(inti=0,n=a.length;i

    n=a.长度;
    对于(int i=0;i
    这种优化在多大程度上是由编译器执行的,而不是由抖动执行的,我不知道,特别是如果它是由抖动执行的,我希望所有3个都会生成相同的本机代码


    然而,第一种形式也可以说更容易被人们阅读,所以我想说还是这样吧。

    我在午餐时有点时间:

    public static void main(String[] args) {
        final int[] a = new int[250000000];
        long t;
    
        for (int j = 0; j < 10; j++) {
            t = System.currentTimeMillis();
            for (int i = 0, n = a.length; i < n; i++) { int x = a[i]; }
            System.out.println("n = a.length: " + (System.currentTimeMillis() - t));
    
            t = System.currentTimeMillis();
            for (int i = 0; i < a.length; i++) { int x = a[i]; }
            System.out.println("i < a.length: " + (System.currentTimeMillis() - t));
        }
    }
    
    publicstaticvoidmain(字符串[]args){
    最终整数[]a=新整数[250000000];
    长t;
    对于(int j=0;j<10;j++){
    t=System.currentTimeMillis();
    对于(inti=0,n=a.length;i
    结果是:

    n = a.length: 672
    i < a.length: 516
    n = a.length: 640
    i < a.length: 516
    n = a.length: 656
    i < a.length: 516
    n = a.length: 656
    i < a.length: 516
    n = a.length: 640
    i < a.length: 532
    n = a.length: 640
    i < a.length: 531
    n = a.length: 641
    i < a.length: 516
    n = a.length: 656
    i < a.length: 531
    n = a.length: 656
    i < a.length: 516
    n = a.length: 656
    i < a.length: 516
    
    n=a.长度:672
    长度:516
    n=a。长度:640
    长度:516
    n=a。长度:656
    长度:516
    n=a。长度:656
    长度:516
    n=a。长度:640
    长度:532
    n=a。长度:640
    长度:531
    n=a。长度:641
    长度:516
    n=a。长度:656
    长度:531
    n=a。长度:656
    长度:516
    n=a。长度:656
    长度:516
    
    注:

  • 如果您反转测试,则
    n=a.length
    显示比
    i
    快大约一半,可能是由于垃圾收集(?)
  • 我无法使
    250000000
    大得多,因为我在
    270000000处获得了
    OutOfMemoryError

  • 关键是,这是每个人都在做的事情,你必须在内存不足的情况下运行Java,但你仍然看不到这两种方法在速度上的显著差异。把你的开发时间花在真正重要的事情上。

    Array.length是一个常量,JIT编译器应该在这两种情况下都能看穿它在这两种情况下,我们都希望生成的机器代码是相同的。至少对于服务器编译器是一样的。

    在这种情况下,为什么不做一个反向循环:

    for (int i = a.length - 1; i >= 0; --i) {
        ...
    }
    
    这里有两个微优化:

    • 环路反转
    • 后缀减量

    @ jjngy:不能调用“代码>数组”,长度< /COD>是O(1),仍然比 int Le=数组长度。i> LeN;< /C> >,也就是O(1)?嗯,如果你担心这些事情,你应该用C或C++ IMHO编程(但是,是的,你可能是对的)JJNGYE:只是迂腐,指出所有O(1)。“一个现代的编译器很可能会立即优化对
    .length
    的调用。”[引文需要]+1。除非你在循环中做一些非常琐碎的事情,否则你在循环中所做的一切都是错误的
    n = a.length: 672
    i < a.length: 516
    n = a.length: 640
    i < a.length: 516
    n = a.length: 656
    i < a.length: 516
    n = a.length: 656
    i < a.length: 516
    n = a.length: 640
    i < a.length: 532
    n = a.length: 640
    i < a.length: 531
    n = a.length: 641
    i < a.length: 516
    n = a.length: 656
    i < a.length: 531
    n = a.length: 656
    i < a.length: 516
    n = a.length: 656
    i < a.length: 516
    
    for (int i = a.length - 1; i >= 0; --i) {
        ...
    }