用于循环优化的Java

Mat*_*ian 5 java optimization

Java Runtime会对以下代码片段执行什么样的优化?字节码没有显示任何优化,但我觉得Java应该采用for循环的最后一个值而不运行整个for循环,因为String是一个基本的Java类.

注意.这个问题是在课堂考试中提出来的; 但是,我无法提供足够的证据来支持我的主张.

public class Main {

    public static void main(String[] args) {
        String str = null;
        for (long i = 0; i < 10000000000L; i++) {
            str = new String("T");
        }

        System.out.println(str);
    }
}
Run Code Online (Sandbox Code Playgroud)

dan*_*368 1

虽然我无法准确说出 jit 编译器正在做什么,但您要求它执行的优化(以确定完全跳过循环体是安全的)实际上非常难以做到,因此我非常怀疑它已经完成了。无论 String 是“基本 Java 类”,情况都是如此。

为了更好地理解,首先我们假设我们正在创建任意类 Foo 的实例,而不是 String。只有当我们知道两件事时,跳过所有这些 Foo 对象的创建才是安全的:调用new Foo()没有任何可观察到的副作用;并且没有对 Foo 的引用“逃逸”循环体。

一个可观察到的副作用类似于设置静态成员的值(例如,如果 Foo 类保留所有Foo()被调用次数的静态计数)。引用转义的一个例子是如果this内部的变量Foo()被传递到其他地方。

请注意,仅仅查看 是不够的Foo(),您需要查看 Foo 的超类的构造函数(以及一直到 Object 的链)。然后您需要查看在每个对象初始化时执行的所有代码。然后查看该代码调用的所有代码。“及时”进行的分析量将非常巨大。

public class Foo extends Bazz{
    static int count = 0;

    public Foo(){
        // Implicit call to Bazz() has side effect
        count++; // side effect
        Bazz.onNewFoo(this); // reference escaping
    }

    Bazz bazz = new Bazz();  // side effect
    {
        Bazz.onNewBazz(this.bazz); // reference escaping
    }
}

class Bazz{
    static int count = 0;

    static List<Foo> fooList = new LinkedList<>();
    static List<Bazz> bazzList = new LinkedList<>();

    static void onNewFoo(Foo foo){
        fooList.add(foo);
    }

    static void onNewBazz(Bazz bazz){
        bazzList.add(bazz);
    }

    public Bazz(){
        count++;
    }
}
Run Code Online (Sandbox Code Playgroud)

您可能认为我们应该让 javac 为我们做这个分析和优化。问题是,无法保证Foo()编译时类路径上的版本与运行时类路径上的版本相同。(这是 Java 的一个非常有价值的功能 - 它允许我将应用程序从 Glassfish 移动到 Tomcat,而无需重新编译)。所以我们不能相信在编译时完成的分析。

最后,认识到 String 与 Foo 没有什么不同。我们仍然需要运行该分析,并且无法提前进行该分析(这就是为什么我可以升级 JRE 而无需重新编译我的应用程序)