web-dev-qa-db-ja.com

パフォーマンスを改善するためにJNIを使​​用して一部のJavaコードをC ++に書き直すことは良い考えですか?

C++でいくつかのJava関数を書き直してみましたが、 [〜#〜] jni [〜#〜] を使用して呼び出しました。 JNIオーバーヘッドのため、Java関数に比べてネイティブC++関数の実行には時間がかかることがわかりました。

C++にはJavaに比べて特定の利点があると広く信じられているため、Javaアプリケーションの全体的なパフォーマンスを向上させる目的で、JavaコードをC++に書き換えるかどうかを知りたいと思いました。良いアイデア?

はいの場合、アプリケーションのどの部分を書き換える必要があり、Javaアプリケーションはそれをどのように使用できますか?

6
Sorter

私はそれに反対します。最新のリリースでは、JVMは非常に改善されており、一般的な製品コードのパフォーマンスの違いはごくわずかです。さらに、JNI自体がパフォーマンスPOVから解放されているわけではなく、全体としては、パフォーマンスを失うのではなく(ケースで判明したように)パフォーマンスが低下します。これに加えて、ネイティブコードは安全ではなく(メモリが破損している可能性があります)、移植性が低く、デバッグが困難です。

従来の手法(より優れたアルゴリズムとデータ構造、最適化、I/Oオーバーヘッドの削減など)とJava手法(JVMチューニング)によってパフォーマンスを向上させてください。ネイティブコードにレガシーAPIがある場合のみまたは、大規模な計算の広範なタスクを実行する必要がある場合はJNIをお勧めします。

さらに参考になる参考情報として、Joshua BlochのEffective Java(第2版)の項目54:ネイティブメソッドを慎重に使用するも参照してください。

14
m3th0dman

標準のJava(デスクトップ)アプリケーションとAndroidアプリケーションの両方でJNIを時々使用しました。その要点は次のとおりです。

1。あなたの質問は、パフォーマンスがJNIによって改善されるかどうかを具体的に尋ねます。パフォーマンスが向上するいくつかの特定の状況があります。 98.3%の場合、これは当てはまりません。また、JNIをパフォーマンスの向上のためだけに追加すると、プロジェクトが非常に複雑になります(JavaまたはC/C++で記述するだけの場合と比較して):非常に優れたツール(IDE、プロジェクト管理ツール、ライブラリ、テストツールなど)(JavaおよびC++のみのプロジェクトの場合と同様)Javaのみのプロジェクト。ただし、混合(Java)+(JNI)+(Cおよび/またはC++)プロジェクトをすべて一度に処理できるツールは、はるかに少ない(そして、私見では品質が低い)。多くの場合、プロジェクトのJava部分に別のツールを持ち込み、プロジェクトのC/C++部分に別のツールを持ち込み、カスタムツールの開発(スクリプトやそのような)あなたのJNIパーツ。

次に例を示します。最近、コードの約90%がJavaプロジェクトで BigDecimal および BigInteger クラスを使用する友人を支援しました。 + // *だけでなく、対数、平方根、および今覚えていないものも含めて、コードは多くの一般的な(そしてよりエキゾチックな)代数演算を行いました。また、JavaのBigXXX APIの外で使用していた機能に気付いた後、コードのこれらの部分を [〜#〜] mpfr [〜#〜] ライブラリを使用するJNIおよびCコードに置き換えてみましたこのライブラリにも存在していました。要するに、この特定のケースでは、パフォーマンスの向上は約10〜15倍でした。最後に、モジュール全体をCに実装し、UIにJavaのみを使用し、新しいCモジュールへの非細分JNI呼び出しのみを使用することを決定しました。

2。 JNIを使​​用する最大の理由は、Javaコードと統合する必要のある複雑なCおよび/またはC++コードがすでにたくさんあるかどうかです。これが当てはまる1つの場所は、既存のビデオゲームをAndroidプラットフォームに移植する場合です。ほとんどのゲームはC/C++で作成されています。 Androidは、その核心部分がLinuxカーネルで実行され、C/C++コードを処理しますが、実際にはJava AP​​I(Java開発環境は、JDK/JVMに非常に似ていますPC/Macにインストールします)。このような状況では、古いゲームをJavaで実行して実行するために、既存のC++コードの薄いAndroidラッパーを実行する方が、すべてのC/C++コードをJava完全に。 Javaシンラッパーアプローチでは、パフォーマンスが低下しますが、元のゲームのリソース要求などによっては、無視できる場合もあります。

これについて Androidのドキュメント からの引用です:

NDKをダウンロードする前に、NDKがほとんどのアプリに役立たないことを理解する必要があります。開発者は、その利点と欠点をバランスさせる必要があります。特に、Androidでネイティブコードを使用しても、通常、顕著なパフォーマンスの向上は見られませんが、常にアプリが複雑になります。一般に、NDKは、アプリに不可欠な場合にのみ使用する必要があります。単にC/C++でプログラミングすることを好むからではありません。

(悪い)例(最後のポイントを示しています):JavaでA *パ​​スファインディングアルゴリズムを実装しました。また、Androidアプリケーションとして、小さくてシンプルなグラフィカルなデモも作成しました。次に、同じアルゴリズムをCに実装しました。JavaとCコードのベンチマークを別々に実行すると、Cが2〜3倍高速になる場合がありました(特に、Javaコード)。そこで、すべてのJava Androidアプリを変更して、JNI経由でCコードを使用するようにしました。プロジェクトはかなり複雑になりましたが(優れた Sequoyah Eclipseプラグインを使用している場合でも)、実際のパフォーマンスの向上は10〜20%になりました。この特定のコードのJavaおよびCバージョンを個別に実行する場合。

以前のAndroidの本(Androidバージョン2時代から)のいずれか(およびここではメモリから引用)は、Quake C++ソースコードを使用してJNIを使​​用する高度な例を示しています約20ページでAndroidアプリにする(約2〜3時間の作業)。代わりに、Quake C++コードがすべてJava(数百行のコード行)に変換された場合、それよりもはるかに時間がかかります。そして、当時のAndroidデバイスでさえ、JNIがQuakeゲームを呼び出すことに伴うパフォーマンスのペナルティを「隠す」ことができたため、ここでJNIを使​​用することは、適切なトレードオフになりました。

10
Shivan Dragon