• スポンサードリンク

Androidでネイティブオブジェクトへのポインタを保持する時の型って?

Android NDK

結論を先に書いちゃうと、ネイティブ側のオブジェクトへのポインタをJava側で保持する場合には、long型を使いましょうってことでした。

ARMの現行のアーキテクチャだと32ビットレジスタしか無いんだから当然ポインタのビット幅も32ビット。つまり現行のARMで動かしている限りはポインタは全部32ビット幅です。だったらint(Javaでは符号付き32ビット整数型)でいいんじゃね?って思いますよね。

なんでそんな事が気になったかというと、ARMのアーキテクチャ(armeabi)では16本有る32ビットレジスタの内、R0〜R3の4本のみが関数の引数として使用可能で、32ビット✕4本に収まらない引数はスタックに積まれてしまいます。
実際にはJNIEnv *envとjobject objの2つが必ず引き渡されてくるので、JNI経由で呼び出す場合に使えるのは32ビット✕2本分、int(jint)やfloat(jfloat)としてであれば2個、long(jlong)なら1個分です。つまりnative側オブジェクトへのポインタをJava側で保持してそのポインタを引数で渡すようにすると、残りの引数は必ずスタックに積まれてしまい余計なオーバーヘッドが増えるんじゃなかなって思います。

ネットをウロウロしたり、Androidのソースを覗いたりすると、intな人もlongな人もいるようです(Androidのソースはlong)。ってことで、JNIでネイティブオブジェクトへのポインタを引き渡すときの型って何がいいんだろうと思い確認してみました。

ちなみにJNI Tips | Android Developersにはこんな風に書いてあります。

64-bit Considerations
Android is currently expected to run on 32-bit platforms. In theory it could be built for a 64-bit system, but that is not a goal at this time. For the most part this isn’t something that you will need to worry about when interacting with native code, but it becomes significant if you plan to store pointers to native structures in integer fields in an object. To support architectures that use 64-bit pointers, you need to stash your native pointers in a long field rather than an int.

簡単に訳すと、

Androidは現在は32ビットシステム上で動かすことを想定している。64ビットシステムとしてビルドすることは理論的には可能だが現時点での目標ではない。なので64ビット対応は殆どの場合考慮する必要はない。しかしもし(Java)オブジェクトの整数型のフィールドにネイティブのポインター値を保持しようとしているのであれば真剣に考える必要がある。64ビットのポインターを保持するにはint型ではなくlong型のフィールドに保持する必要がある、みたいな感じですね

テストのために、適当に計算した数値を返すだけのメソッドfuncを持ったサンプル用のクラスを考えてみます。
もちろん、こんな処理に本来はnative codeは必要ありませんし、使うべきではないですが。
ネイティブ側で呼ばれた回数を保持するフィールドを持った構造体を確保して、その構造体のインスタンスへの参照(ポインタ)をid代わりにJavaオブジェクト側で保持します。

« »

  • スポンサードリンク

%d人のブロガーが「いいね」をつけました。