1. 序章

この記事では、組み込み関数とは何か、およびJavaやその他のJVMベースの言語でどのように機能するかを学習します。

2. 組み込み関数とは何ですか?

組み込み関数は、プログラミング言語のコンパイラーまたはインタープリターによる特別な処理を行う関数です。 具体的には、コンパイラーまたはインタープリターがさまざまな理由で関数を代替実装に置き換えることができる特殊なケースです。

プログラミング言語は通常、特定のメソッド呼び出しが特別であり、このメソッドを呼び出すたびに結果の動作が異なることを理解することによってこれを処理します。 これにより、コードは通常と変わらないように見えますが、プログラミング言語の実装が特別な場合に介入して、追加の利点を提供することができます。

正確な動作方法は、プログラミング言語間、およびオペレーティングシステムとハードウェア間で異なります。 ただし、これらは私たちのために処理されるため、通常、これらの詳細を知る必要はありません。

組み込み関数にはさまざまな利点があります。 特定のアルゴリズムをネイティブコードに置き換えると、パフォーマンスが向上したり、オペレーティングシステムの特定の機能や基盤となるハードウェアを活用したりすることができます。

3. JVMの組み込み関数

JVMは、正確なクラスの正確なメソッド呼び出しを代替バージョンに置き換えることにより、組み込み関数を実装します。 JVMはこれ自体を処理するため、コアクラスと特定のアーキテクチャでのみ機能します。 また、クラス全体ではなく、特定のメソッドのみをスワップアウトすることもできます。

これがどのように機能するかは、JVMによって異なります。 これには、JVMの異なるバージョン(Java 8と)だけではありません。 たとえば、Java11。 これには、さまざまなJVMターゲット(Linuxと。 たとえば、Windows、特にJVMベンダーはOracleと IBM。 場合によっては、JVMに渡される特定のコマンドラインフラグがそれらに影響を与える可能性があります。

この多様性は、アプリケーションのみに基づいて、どのメソッドが組み込みに置き換えられ、どのメソッドが置き換えられないかを判断する方法がないことを意味します。 これは、アプリケーションを実行しているJVMによって異なります。 ただし、これにより、場合によっては驚くべき結果が生じる可能性があります。使用するJVMを変更するだけでパフォーマンスが大幅に向上するなどです。

4. パフォーマンス上の利点

組み込み関数は、同じコードのより効率的なバージョンを実装するためによく使用されます。たとえば、実行中のOSまたはCPUの実装の詳細を活用します。 これは、より効率的な実装を使用できる場合もあれば、ハードウェア固有の機能を使用できる場合もあります。

たとえば、HotSpot JDKには、java.lang.Mathの多くのメソッドに固有の実装があります。 正確なJVMに応じて、これらはCPU命令を使用して実装され、必要な正確な計算を実行する可能性があります。

簡単なテストでこれを実証します。 たとえば、 java.lang.Math.sqrt()を取ります。 テストを書くことができます:

for (int a = 0; a < 100000; ++a) {
    double result = Math.sqrt(a);
}

このテストでは、平方根演算を100,000回実行します。これには、約123msかかります。 ただし、このコードを Math.sqrt()の実装のコピーに置き換えると、次のようになります。

double result = StrictMath.sqrt(a);

このコードは同じことをしますが、代わりに166msで実行されます。 これは、JVMが実装を組み込みバージョンに置き換えるのではなく、実装をコピーすることで35%の増加です。

5. 不可能な実装

その他の場合、組み込み関数は、コードをJavaで実装できない状況で使用されます。 これらは通常、非常に低レベルのケースのために予約されています。

たとえば、 java .lang.ThreadクラスのメソッドonSpinWait()を見てみましょう。 このメソッドは、このスレッドが現在作業を実行しておらず、CPU時間を別のスレッドに割り当てることができることを示しています。 これを実装するには、可能な限り低いレベルで動作する必要があります。

HotSpot JDK for x86アーキテクチャは、PAUSEオペコードを使用してこれをCPUに直接実装します。これを実現する他の唯一の方法は、ネイティブコードへのJNI呼び出しを使用することでした。そして、これに伴うオーバーヘッドは、そもそも通話のメリットを損なうことになります。

6. Javaでの組み込み関数の識別

残念ながら、組み込みバージョンに置き換えられる可能性のあるメソッドを識別する保証された方法はありません。これは、異なるJVMまたは異なるプラットフォーム上の同じJVMでさえ異なるメソッドに対してこれを行うためです。

ただし、Java9以降のHotspotJVMを使用する場合、 @HotSpotIntrinsicCandidate アノテーションは、置き換えられる可能性のあるすべてのメソッドで使用されます。 このアノテーションを追加しても、メソッドが自動的に置き換えられるわけではありません。 実際には、これは基盤となるJVM内で発生します。 代わりに、JVM開発者は、これらのメソッドが特別であり、注意する必要があることを知っています。

他のJVMは、識別された場合、これを異なる方法で処理する可能性があります。 これには、Java8以前のホットスポットJVMが含まれます。

7. 概要

組み込み関数がランタイムJVMで使用可能かどうかを知る方法がないため、組み込み関数の存在に依存するようにプログラムを作成することはできません。 ただし、これらは、JVMがプログラムの動作方法を改善するために使用できる説得力のあるアプローチです。

これらの組み込み関数は、JVMの新しいバージョンに追加できます(多くの場合、追加されます)。 これにより、実行中のJVMをアップグレードするだけで、すでに実行中のコードを改善できます。これは、依存関係と実行時間を最新の状態に保つためのもう1つの理由です。