因此,我们都知道,Java解释缓慢且C的编译和优化运行速度非常快。 您可能知道,图片截然不同。

TL; DR Java适用于星座,它的速度更快,因为JIT可以执行内联,因为所有方法/功能都是可见的,而C编译器无法跨编译单元(例如库等)执行优化。

一次写入,随处运行

写一次,到处等待 ”,因为解释器会很慢。 因此,现代JVM要做的就是及时编译。 这意味着JVM在内部将字节码转换为用于CPU的机器代码。 但是由于此过程非常复杂,因此Hotspot JVM (最常用的一种)仅对经常执行的代码片段执行此操作(因此命名为Hotspot

现在,在查看我的完整示例之前,请注意,Java具有许多功能,例如动态调度(在接口上调用方法),它还带有运行时开销。 因此,Java代码可能更容易编写,但通常仍会比C代码慢。 但是,当涉及纯数字运算时,就像下面的示例一样,有一些有趣的发现。

因此,无需进一步讨论,这是示例C代码:

test.c:

int compute(int i);

int test(int i);
 
int main(int argc, char** argv) {
    int sum = 0;
    for(int l = 0; l < 1000; l++) {
        int i = 0;
        while(i < 2000000) {
            if (test(i))
            sum += compute(i);
            i++;
        }   
    }
    return sum;
}

test1.c:

int compute(int i) {
    return i + 1;
}

int test(int i) {
    return i % 3;
}

现在,主要功能的实际计算完全不重要。 关键是它经常调用两个函数(测试和计算),并且这些函数在另一个编译单元(test1.c)中。 现在让我们编译并运行程序:

> gcc -O2 -c test1.c

> gcc -O2 -c test.c

> gcc test.o test1.o

> time ./a.out

real    0m6.693s
user    0m6.674s
sys    0m0.012s

6.6秒

Test.java

public class Test {

    private static int test(int i) {
        return i % 3;    }

    private static int compute(int i) {
        return i + 1;    }

    private static int exec() {
        int sum = 0;        for (int l = 0; l < 1000; l++) {
            int i = 0;            while (i < 2000000) {
                if (test(i) != 0) {
                    sum += compute(i);                }
                i++;            }
        }
        return sum;    }

    public static void main(String[] args) {
        exec();    }
}

现在让我们编译并执行以下命令:

> javac Test.java

> time java Test

real    0m3.411s
user    0m3.395s
sys     0m0.030s

3.4秒的时间

那么,这是一个在现实生活中从未发生过的完全异国情调的虚构例子吗? 是的,没有。 当然,这是一个极端的情况,但是请考虑一下代码中包含的所有库。 所有这些方法都不能在C语言中进行优化,而在Java中,字节码的来源无关紧要。 由于所有JIT都存在于正在运行的JVM中,因此JIT可以对其核心内容进行优化。 当然,C语言有一个卑鄙的技巧可以减轻这种痛苦:Marcos。 在我看来,这就是市长的原因之一,为什么C中如此之多的库仍然使用宏而不是适当的功能-伴随着它们带来的所有问题和麻烦。

现在就在火焰战争开始之前:这两种语言都有其长处和短处,并且在软件工程领域都占有一席之地。 撰写这篇文章仅是为了吸引您的注意,并想知道现代JVM每天都在发生。