为什么Java 比 C++ 慢?

海外服务器 (462) 2015-11-24 14:06:00

     了回答这个问题,需要先将该问题分成几个可能引起慢的原因:

      垃圾回收器。这是一把“双刃剑”。如果你的程序遵循“大部分对象都在年青代中消亡”模型,垃圾回收器是非常有利的(很少的碎片,更好的缓存局部性)。但是,如果程序不遵循该模型,JVM将花费很多资源来回收堆内存。

      大对象。在Java中,所有的对象都有一个vtable指针,而C++中使用POD结构没有额外开销。此外,所有的Java对象是可以被锁定的。其 实现依赖于JVM,这可能需要在对象中增加额外的字段。大对象 == 缓存更少的对象 == 更慢。(另一方面,Java 7 用64位记录压缩后的指针,这也是造成该问题的一部分原因。

缺乏内联对象。在Java中,所有的类都是指针。在C++中,对象可以和其它对象一起分配,或者在栈上分配。这样可以提高缓存的局部性,从而减少动态内存分配的开销。

平台函数调用。在Java中,JNI的调用或者将对象编译成本地代码都会带来不小的开销。如果你需要频繁调用客户端的C++代码,会增加很大的开销。

低效的强制抽象。例如,在Java中字符串是不可变的。如果你想写一个XML分析器,你只使用String对象(没有char[]),它将会很慢,因为需要分配额外的空间。

虚函数调用增加。JVM中,几乎所有的函数调用都是虚函数调用。有许多代码尝试避免虚函数调用,但是很多场景下,JVM无法解决这个问题。这阻碍了代码的内联,使代码变慢。

缺乏高级的编译特征及转为汇编的能力。 如果你写了一段能从汇编得益的代码Java可能表现不佳。

在我看来,最大的问题是垃圾回收。在程序中,强制在大的内存中进行多次完全GC,是最容易导致Java和C++之间产生鸿沟的原因之一。除此之外,如果将程序的工作集放在L2缓存之外,像大对象、缺乏内联对象等问题,也会导致两者之间的巨大差别。

      低效的强制抽象和平台函数也会导致速度下降,但是这通常只会因为低级的代码才会产生。如果你使用写得很好的Java代码库,这通常不是什么大问题。

THE END