关于Java对于for循环的优化问题

在代码大全中看到了一个观点:越繁忙的循环应该放在最内部,可以减少初始化的次数,随即我在Java中进行验证,但是结果却恰恰相反

public class Main {
    public static void main(String[] args) {
        int sum = 0;
        final int big = 10000000;
        final int small = 10;
        long l = System.nanoTime();
        for(int i = 0;i < big;i++){
            for(int j = 0;j < small;j++){
                //sum++;
            }
        }
        System.out.println("big out : " + (System.nanoTime() - l));

        l = System.nanoTime();
        for(int i = 0;i < small;i++){
            for(int j = 0;j < big;j++){
                //sum++;
            }
        }
        System.out.println("big in  : " + (System.nanoTime() - l));
    }
}

最终的打印结果为:

big out : 5119088
big in  : 15178535

明显是for循环在外部的更快,看了很多帖子也没有头绪,请问这是因为JVM对于for循环的优化导致的吗?

循环到底谁放在里面谁放在外面,主要是考虑2个问题:
(1)分支预测命中率,如果小循环放在内侧,意味着一会儿循环,一会儿跳出循环,会让分支预测不准,导致一些开销
(2)缓存命中率,比如说对于二维数组操作,按照行来操作,每个内循环内再按照列来操作,这样其实是连续访问内存的,反过来的话,就跳跃存取内存,那么缓存失败的概率比较高,导致开销
但是这个都是经验之谈,硬件的发展是突飞猛进的。比如说在代码大全编写的2000年,Pentium III处理器只有16KB一级缓存,P4更是减少到8KB,而现在的处理器甚至有64KB一级缓存了,二级缓存更不用说了。
而现在的JVM和CPU,也会根据大多数的代码,用大数据的方式做了优化,因此程序员刻意使用某种技巧的意义越来越小。
你这种空循环的测试,并不具有任何典型性。

  • 你可以看下这个问题的回答https://ask.csdn.net/questions/7684476
  • 这篇博客也不错, 你可以看下面试:精通Java;面试官:来讲一下JVM虚拟机内存模型的最底层原理,必须说详细说清楚,知其所以然。看完后,你还敢在简历上写精通Java吗?
  • 同时,你还可以查看手册:java-集合 - 关于使用和扩展Java集合框架的课程。- 聚合操作 代表你对集合进行迭代,这使你能够编写更简洁和有效的代码,处理存储在集合中的元素。 -平行主义 中的内容
  • 除此之外, 这篇博客: 类的生命周期及静态变量和实例变量的区别中的 一、Java在需要使用类的时候,才会将类加载。如果只是定义一个变量为XXX类型,则不会加载类。Java的类加载是由类加载器来完成,JVM在加载类时,需要经过如下几个步骤: 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • 1、加载:找到相应的class字节码文件,由类加载器将类的信息读入到JVM中。如果找不到该类,则会抛出ClassNotFoundExcetpion异。2、验证:确认读取文件类型的正确性,即class是否符合Java规范并且不会损害JVM的完整性。
    3、准备:为静态成员变量分配内存同时设置默认初始值。【byte、short、int、long类型的默认初始值为0,float、double类型的默认初始值为0.0,char类型的默认初始值为\u0000(空),boolean类型的默认初始值为false,String类型的默认初始值为null】
    4、解析:把符号引用转为直接引用的过程。例如将变量名转为内存地址。以后使用这个成员变量时,就直接去这个内存地址去找了。同时 类的成员方法也会被映射到某个内存地址以待调用。

  • 您还可以看一下 汤小洋老师的手把手搭建Java在线音乐网站【附源码】(毕设)课程中的 在线音乐网站的部署运行小节, 巩固相关知识点
  • 以下回答由chatgpt基于相关博客总结生成:

    对于问题中提到的代码优化问题,建议对实验进行以下步骤和分析:

    1. 根据问题描述,你在实验中将for循环放在外部,并观察到更快的结果。可以尝试调整代码结构,将for循环放在内部,并进行测试和对比,确保实验结果的准确性。

    2. 代码优化的原则是尽量减少不必要的重复计算和初始化操作。当将一个繁忙的循环放在内部时,每次循环迭代都需要初始化循环的条件,这可能导致额外的开销。而将循环放在外部,只需要初始化一次,可以减少重复初始化的时间。

    3. 考虑JVM对于for循环的优化。JVM在加载类时会经过加载、验证、准备和解析的过程,这个过程与for循环的优化关系不大。而for循环本身是Java的基本结构,JVM会对其进行优化,例如使用JIT即时编译技术,将循环部分编译成机器码,加速执行。

    4. 确认实验结果和问题描述的一致性。如果实验结果与问题描述相反,可以考虑是否存在其他因素导致的结果。例如循环体内部的计算量不同、循环次数不同、循环过程中的计算结果是否被使用等。

    综上所述,根据问题描述和给出的参考资料,无法确定具体的解决方案。建议尽量按照上述步骤进行实验和分析,以确定具体的问题原因和解决方案。如果实验结果仍然无法解释,可能需要进一步深入研究Java编译器和JVM的优化机制。