carrays.i を使用している場合、Java 配列間でコピーを行ったり来たりしていないという前提があります。その代わりに、どこでも carrays.i タイプを使用する必要があります。
測定できるオーバーヘッドにはまだ 2 つのタイプがあります。JNI 呼び出しは特定のペナルティを被り、別のペナルティをコピーします。carray.i を使用すると、正確に識別したように、JNI 呼び出しの価格が低く抑えられます。Get<PrimitiveType>ArrayElements
さらに、JVM によっては、への呼び出しによってコピーが導入される場合もあります。
しかし驚くべきことは、arrays_java.i の実装が他の方法で予想されるよりも多くのコピーを作成することです。たとえば、typemap で使用される SWIG_JavaArrayIn 関数には次のものが含まれます。
for (i=0; i<sz; i++)
JAVA_TYPEMAP_ARRAY_ELEMENT_ASSIGN(CTYPE)
また、同様の対応するコピー (代入による) が出力タイプマップでも発生しています。
for (i=0; i<sz; i++)
arr[i] = (JNITYPE)result[i];
(これは、JVM がコピーを作成した可能性に加えてです!)
ただし、これらすべての理由は適切です。これらの型マップは、使用されている JNITYPE が C 型に正確にマップされない「奇妙な」ケースをサポートする必要があります。これが発生する可能性のある例は、の配列の場合ですunsigned char
- Java で最も近い型は ですがbyte
、byte
署名されているため、値の範囲を表すためにunsigned char
、C の の配列short
は Java 側での配列として公開されます。 . メモリ配置に互換性がなくコピーが必要なためsizeof(jshort) != sizeof(unsigned char)
、記入して返却する必要があります。
これが気になる場合は (ベンチマークを強くお勧めします)、希望どおりに JNI 呼び出しを使用する独自の効率的な型マップを作成することもできます。次に例を示します。
%module test
%typemap(jtype) int arr[ANY] "int[]"
%typemap(jstype) int arr[ANY] "int[]"
%typemap(jni) int arr[ANY] "jintArray"
%typemap(javain) int arr[ANY] "$javainput"
%typemap(in) int arr[ANY] {
// check the size is compatible here also
$1 = JCALL2(GetIntArrayElements, jenv, $input, 0);
}
%typemap(freearg) int arr[ANY] {
if ($1) {
JCALL3(ReleaseIntArrayElements, jenv, $input, $1, JNI_ABORT);
}
}
%typemap(argout) int arr[ANY] {
JCALL3(ReleaseIntArrayElements, jenv, $input, $1, 0);
$1 = NULL;
}
%inline %{
void populate(int arr[100000]) {
for (unsigned i = 0; i < 100000; ++i) {
arr[i] = -i;
}
}
%}
VM から取得した Java 配列へのポインターを渡します (まだコピーである場合とそうでない場合があります。オプションの 3 番目の引数で確認できます。GetIntArrayElements
これは、JVM がプロセスでコピーを作成したかどうかを示すブール値です)。
これらの型マップは、Java 配列を「そのまま」渡し、JVM からポインタを取得して C 関数内で使用します。関数が成功ReleaseIntArrayElements
すると、3 番目のパラメータが 0 で呼び出されます。これにより、変更が Java 内でも確実に表示されます。呼び出しが失敗した場合、関数が呼び出されJNI_ABORT
、返されたポインターがコピーであった場合、変更が表示されません。
次のように呼び出すことができます。
public class run {
public static void main(String[] argv) {
System.loadLibrary("test");
int[] arr = new int[100000];
test.populate(arr);
// Only print 40 to avoid spamming my screen!
for (int i = 0; i < 40; ++i) {
System.out.println(arr[i]);
}
}
}
コピーが 0 になる可能性がありますが、Java の型が C の対応する型と完全に一致する場合にのみ使用できます。