Java にオブジェクトの配列があり、ネイティブ C コードがその配列に直接アクセスできるようにしたい (コピーまたはアクセサー関数なし)。これは可能ですか?ソリューションが JVM 固有のものであるかどうかは気にしません。
4 に答える
もちろんJNIでも可能です。
このリンクを参照する価値があります: http://journals.ecs.soton.ac.uk/java/tutorial/native1.1/implementing/array.html 要するに -
#include <jni.h>
#include "IntArray.h"
JNIEXPORT jint JNICALL
Java_IntArray_sumArray(JNIEnv *env, jobject obj, jintArray arr)
{
jsize len = (*env)->GetArrayLength(env, arr);
int i, sum = 0;
jint *body = (*env)->GetIntArrayElements(env, arr, 0);
for (i=0; i<len; i++)
sum += body[i];
(*env)->ReleaseIntArrayElements(env, arr, body, 0);
return sum;
}
新しいバージョンの Java を使用している場合は、ByteBufferオブジェクトを使用してください。
呼び出しByteBuffer.allocateDirect()
てバッファを割り当てます。ダイレクト バッファは、ガベージ コレクタのドメインの外側にあります。JNI からバッファにアクセスするには、 を呼び出しますGetDirectBufferAddress()
。バイトバッファへのポインタを返します。これは内部でコピーを行いません。バッファへの変更は、Java およびネイティブ側で見られます。
Javadoc には、ダイレクト バッファの使用に関するいくつかの警告があります。
ダイレクト バイト バッファは、このクラスの allocateDirect ファクトリ メソッドを呼び出すことによって作成できます。このメソッドによって返されるバッファーは、通常、非直接バッファーよりも割り当てと割り当て解除のコストが多少高くなります。ダイレクト バッファーの内容は、通常のガベージ コレクション ヒープの外に存在する可能性があるため、アプリケーションのメモリ フットプリントへの影響は明白ではない場合があります。したがって、ダイレクト バッファは、主に、基盤となるシステムのネイティブ I/O 操作の対象となる、大きくて存続期間の長いバッファに割り当てることをお勧めします。一般に、ダイレクト バッファを割り当てるのは、プログラムのパフォーマンスが測定可能な程度に向上する場合にのみ行うのが最善です。
私はついに答えを見つけました。通常、JNI で私が望んでいたことを行うことはできません。ただし、一部の VM は必要な機能を提供します。私は JikesRVM を使用しました。
1) ネイティブ コードは、配列のメモリ位置を必要とします。これは、JikesRVM の「Magic」機能を使用して実現できます。これは、各オブジェクトのメモリ アドレスを取得できる ObjectReference と Address クラスを提供します。次に、このアドレスを (JNI を使用して) long/int 引数としてネイティブ コードに転送し、そこでポインターにキャストすることができます。
2) GC はオブジェクトを移動しない場合があります。これは、GC でのピニングのサポートが必要なため、もう少し注意が必要です。JikesRVM の場合、オブジェクトに @NonMoving および @NonMovingAllocation (これも「マジック」の一部) のアノテーションを付けることができます。さらに、8KB を超えるオブジェクト (つまり、配列) は、オブジェクトを移動しないラージ オブジェクト スペースに配置されます。
上記のすべての質問には、適切な解決策があります (リンクの下をクリック)。
プリミティブ配列の代わりにオブジェクトがある場合、直接アクセスを提供する方法を見つけることができます。