Java vs Golang
軽量モデルによる違い
Goは、軽量スレッド(ゴルーチン)
Javaは、OSスレッド(プラットフォームスレッド)
※ ちなみにjdk21では、バーチャルスレッドという軽量スレッドも使用できる。
これによりjavaでも高いスループット性能が出せる
コンパイルの違い
前提
AOT ... Ahead of time
JIT ... Just in time
Java(2段階コンパイル)
静的言語だが、2段階でコンパイルが行われている
-
初期コンパイル(開発時のコンパイル)
開発者がソースコード(.javaファイル)を記述した後、JavacなどのJavaコンパイラを使って行う作業。JVM上で動作可能な中間言語を生成し、型の安全性などをチェックします。
ここで生成されるバイトコード(.classファイル)はどのCPUでも解釈できる共通の形式。 -
実行時コンパイル(JIT)
これはプログラムが実行され、JVMがバイトコードをロードした後に行われる作業です。
「入力:バイトコード」に対して、「出力:実行しているCPU(Intel, Arm)向けのネイティブマシン語」が返ってきます。
1では型の安全性などをチェックしていましたが、こちらではそれぞれの環境でいかに最適化できるかを目指します。
Go
一方でGoは下記の通り、実行前に(最適化含め)全てのコンパイルが完了します。
Goは実行前にコード全体をターゲットのOSとCPUに合わせたネイティブなマシン語に変換します。(AOTコンパイル)
最適化が実行前に完了するため、起動直後から最高レベルの性能を発揮します。
Javaのように実行中にコンパイルや最適化のオーバーヘッドが一切発生しないので、
- パフォーマンス予測可能
- パフォーマンス安定
が特徴
OS以外の特別なソフトウェアへの依存性
Java
JVMがないと動きません。
Javaのプログラムを実行するには、JVMという大規模なソフトウェア実行環境がインストールされていることが必須です。
JVMはJavaのバイトコードを実行環境に合わせて解釈・実行し、メモリ管理(GC)やスレッド管理を行います。
厳密には(中間コードを生成するために)javacも必要なので、JDKが必要です。
Go
Goは、コンパイル時にプログラムが依存するライブラリやGoランタイム(GC、スケジューラーなど)のコードを実行コードと一緒に直接組み込んで、コンパイル時に最終的な実行可能ファイルに全てひとまとまりにしてしまう。
なので、事前にソフトフェアをインストールする必要がない(OS以外の依存性がない)
また、結果として生成されるのはひとつのファイル(シングルバイナリ)となる。
Discussion