web-dev-qa-db-ja.com

JNIはAndroidでどの程度役に立ちますか?

Java/Androidでは、実行速度を向上させるために、c/c ++言語で記述されたコードを呼び出すことができます。インストール中に(私が知る限り)アプリケーション全体をネイティブコードにコンパイルするAhead Of Timeコンパイルについて聞いたことがあります。

デバイスの計算能力を比較するために、圧縮、暗号化(画像、オーディオ、またはビデオ処理ではない)などのいくつかの数学演算を実行したいとします。そのコードは、Javaおよびc/c ++の両方で記述できます) 。

すべてのJavaコードはAndroidでネイティブに変換されるため、JNI/NDKの使用はありますか?それは何ですか?

Update1:​​ここ 言及されています:

Dalvikとは異なり、ARTは、インストール時にアプリケーション全体をネイティブマシンコードにコンパイルすることにより、事前(AOT)コンパイルの使用を導入します。

暗号化アルゴリズム(ポインターのような言語固有の構成を使用しない)があると考えてください。通常、ネイティブコード(c/cpp)にコンパイルすると、実行速度が最大になります。しかし、引用したように、アプリのインストール時にすべてのコードがネイティブにコンパイルされる場合、暗号化方法(Javaで記述)と(同じ)暗号化機能(cpp)の間にパフォーマンス(速度)の違いがあります。

Androidまたは類似のvmベースのOSで暗号化アルゴリズムを実装するための最良のアプローチを知りたい。

3
pebble

これは単なるAndroidアプリケーションではありません。会社がAndroid、iOS、Windows、MacOS、Linux向けのアプリケーションを必要としていると想定してください。また、共有機能があります。すべてのプラットフォームで利用可能な言語で記述されています。 、それはC++です。

これで、アプリケーションの大部分をJava(およびObjective-CまたはSwift、およびC#、およびLinuxのファッションは何でも)で書き換えることができます)。高価でメンテナンスの悪夢、またはJNIを使​​用したC++コードの使用。

3
gnasher729

JNIが役立つ理由はいくつかあります。

  • ビルド済みのC++ライブラリを使用する
  • 一般に、C++ canは、Javaバイトコードコードが解釈されるものよりも優れたパフォーマンスを提供すると考えられています。C++を使用すると、メモリ使用量をより細かく制御でき、高いパフォーマンスを達成するために意図的に。
1
Samuel

すべてのJavaコードはAndroidでネイティブに変換されるため、JNI/NDKの使用はありますか?それは何ですか?

メモリの制御は私にとって最大のものです。私は見ましたJavaレジスタ割り当てと命令選択の非常に有能な仕事をしますが、パフォーマンスの1つの明白な難しさがあります。それはオブジェクトに関連するオーバーヘッドとメモリレイアウトに与える損失です。それでも、Javaコードのパフォーマンスを通常よりもはるかに高くすることができ、オブジェクトではなく単純な古いデータ型に重点を置くことができれば、失われた多くのコントロールを取り戻すことができます。

たとえば、Cでは次のようなことができます。

_struct Vector
{
    // AoS
    float xyzw[4];
};
_

そして、それらの配列を作成し、コンテンツが常にsizeof(struct Vector)であるストライドに隣接することを保証します。これは、通常、この場合パディングを除外し、sizeof(float)*4またはちょうど128ビットになります。また、128ビット境界に整列されたヒープ割り当てをヒープに割り当て、SIMDレジスタへの整列された移動を使用して、効率的な組み込み関数でコードをベクトル化することもできます。 C++でも同様の方法で、メソッドを使用してベクトルクラスを作成し、利便性のためにオーバーヘッドを支払うことなく、それらの配列が連続していることを保証できます。

ただし、JavaでVectorクラスを作成しようとすると、そのような制御は得られません。各Vectorオブジェクトには、リフレクションや動的ディスパッチなど、Vectorのサイズを拡張するためのメタ情報がいくつか関連付けられます。これらの配列を作成しようとすると、ポインタの配列を作成するのと同じようになり、その時点で、各Vectorインスタンスのクラスメタデータに加えて、ポインタの追加メモリと間接参照コスト、および配列が連続していることは保証されません(最初に、個々のVectorをすべて一度に順番に割り当てた場合、最初に続く可能性がありますが、最初のGCサイクルの後で、メモリ内でフラグメント化できます)。これは、時間的および特に空間的な局所性が失われ、必要以上に多くのキャッシュミスにつながるパフォーマンスキラーになる可能性があります。

そうは言っても、多くの場合、Javaコードを使用すると、コードを大幅に高速化できます。たとえば、floatの配列ではなく、Vectorの巨大な配列を使用するだけの場合、上記のすべてのオーバーヘッドがあり、配列の内容が連続していることを保証できます。実際には、多くの人がJavaアプリケーションをJNIに到達することなく、完全に高性能にするために立っていると思いますオブジェクトではなく、プレーンな古いデータタイプの配列を使用して、JNIで実装したい領域を処理します。便宜上、一度に一連のベクトルを格納するVectorsクラスを作成できます(オブジェクトのオーバーヘッドは、たとえば、ベクターごとではなく、100個のベクターに対して1回だけ支払われ、それらに操作を提供しますが、内部的にはこれらのベクターをfloatの大きな配列として表します。

Java(BVHを含む、パストレース自体のネイティブAPI呼び出しはありません)で実装された、合理的なインタラクティブCPUパストレーサーを見たことさえありました。男性アマチュアプロジェクトですが、ソースコードをじっと見たとき、それはまさにそれでした。単純な古いデータ型の巨大な配列を優先して、パフォーマンスが重要なホットデータのオブジェクトを回避しました。代わりに、VectorおよびMatrixオブジェクトを使用することも避けましたフロートとインデックス範囲の配列を使用します。もちろん、実装はそれほど美しくなく、古い非構造化Cコードによく似ていましたが、これは、低レベルのクリティカルパスと、何十億回もアクセスされたデータに対してのみでした。アプリケーションのレベルレベルの部分はまだオブジェクトでモデル化されていましたが、その実装の詳細によって回避されました。

1
user204677