声明: 本文主要用于揭示Go在某些方面的性能缺陷, 目的在于如何改进和避免这些性能陷阱, 并不意味着Go的性能很差. 欢迎理性评论, 不欢迎无脑黑.
后两期传送点:
《C# vs Java 的一些性能对比》见此链接: C# vs Java 的一些性能对比
《C++ vs Java 的一些性能对比》见此链接: C++ vs Java 的一些性能对比
测试系统: Win10 64-bit; Intel I5-4430 (3GHz)
Go版本: 1.12 (64-bit)
Java版本: 1.8.0_172 (64-bit)
测试说明: 均使用默认参数启动,每个程序均运行3次,取时间最短值,时间包括整个进程的生命周期(对Go有优势)
测试1 (频繁递归函数调用)
Go版本:
Java版本:
输出结果: 1134903170
性能结果: Go: 5.3秒 Java: 3.2秒
解释说明: 此测试主要考察函数调用开销以及小函数内联(包括递归内联)的能力, Go语言貌似没有实现递归内联, 而JVM的JIT可以内联一定程度.
测试2 (频繁接口调用)
Go版本:
Java版本:
输出结果: 1000000000
性能结果: Go: 2.1秒 Java: 0.53秒
解释说明: 此测试主要考察接口调用的开销, 比普通调用增加了一些间接性. JVM因为JIT有动态优化能力, 甚至可以虚函数内联, 而Go语言的静态代码编译无法在运行时做优化, 所以接口调用的开销会多一些.
测试3 (频繁内存分配/垃圾回收)
Go版本:
Java版本:
输出结果: 9999949995000
性能结果: Go: 18.0秒 Java: 3.3秒
解释说明: 此测试主要考察堆内存的分配和GC的综合吞吐量性能. JVM由于支持分代垃圾回收,有很高的短生命期对象的GC性能. 目前Go的GC算法主要优势是停顿短,而不是高吞吐量, 所以在此测试中无法发挥出优势. 另外, Go版本数组存指针的目的在于产生大量对象的分配和GC, 如果不存指针就失去意义了(Java版本的对象变量实际上就是指针).
PS: 考虑到公平性, Go和Java测试程序中的类型和流程基本一致, 如有异议请在评论中不吝指出.