- PR -

JNIを使うときにコンテナはどちら側に?

1
投稿者投稿内容
Jun
大ベテラン
会議室デビュー日: 2003/08/25
投稿数: 141
投稿日時: 2003-10-09 14:45
JNIを始めて使ってみたいのですが,JNIの使い道というとよくプラットフォーム固有の
APIを呼び出したりというような例が多いように思います.

そうした単純な呼び出し程度のことをするためでなく,容量の大きなコンテナを
扱いたいのですが,その方法について質問です.

ネイティブメソッドからC++で定義されたコンテナを扱い,複数のネイティブメソッドを
またがってコンテナの内容を保持したいのですが,そうした方法をとっても問題は発生
しないのでしょうか.
また別な方法としてコンテナはjavaの側で定義し,その要素はc++の側で定義されたクラス
を使い,コンテナの操作はjava側で行い,要素の操作はネイティブコードで行う
といったことは可能でしょうか.
もし両方可能とすればどちらが有利でしょうか

またJNIを使ってコンテナを操作している例などありましたら紹介願えませんでしょうか
ちいにぃ
大ベテラン
会議室デビュー日: 2002/05/28
投稿数: 244
投稿日時: 2003-10-09 17:55
 JNI学習中なので、間違っているかもしれませんが(と言い訳して :))
引用:

ネイティブメソッドからC++で定義されたコンテナを扱い,複数のネイティブ
メソッドをまたがってコンテナの内容を保持したいのですが,そうした方法を
とっても問題は発生しないのでしょうか.


 C++にはガーベッジコレクションがありませんから、ヒープ上に確保したコンテナの
インスタンスは複数のネイティブメソッド間で使えると思います。
[追記]
 とはいえ、Unloadされたとき(JNI_Unloadが呼ばれる)はまずいかも。
 複数のクラスローダが同じネイティブライブラリをロードする‥‥ことは
起こらないそうです。例外が発生するそうです。http://java.sun.com/j2se/1.4/ja/docs/ja/guide/jni/jni-12.html#libmanage

引用:

また別な方法としてコンテナはjavaの側で定義し,その要素はc++の側で
定義されたクラスを使い,コンテナの操作はjava側で行い,要素の操作は
ネイティブコードで行うといったことは可能でしょうか.
もし両方可能とすればどちらが有利でしょうか


 ケースバイケースだと思います。
 コンテナの操作をC++側でやるならC++側コンテナを用意したほうがよいでしょうし、
その逆にJava側で操作するならJava側にコンテナ+要素のProxy、C++側にアクセサを
用意する‥‥と思います。
引用:

またJNIを使ってコンテナを操作している例などありましたら紹介願えません
でしょうか


手元に次の本がありますが載ってないですねえ‥‥。
「The Java Native Interface - Programmer's Guide and Specification」
http://java.sun.com/docs/books/jni/index.html PDFやhtmlでも入手可能)

CommAPIの実装、rxtx http://www.rxtx.org/を眺めてみましたが、単純に
関数を呼んでるだけでしたし。

[ メッセージ編集済み 編集者: ちいにぃ 編集日時 2003-10-09 22:42 ]
Jun
大ベテラン
会議室デビュー日: 2003/08/25
投稿数: 141
投稿日時: 2003-10-10 09:17
早速のご回答ありがとうございます.

どちらも可能であればどちらかといえばコンテナはC++側のクラスを使ったほうが
自分としては作りやすいのですが,その方法がどうもわかりません.

javaのクラスのインスタンスをネイティブ側に渡したりそのフィールドに
ネイティブ側からアクセスしたりする方法はわかるのですが,C++のコンテナを使う場合
ネイティブ側でそのクラスのインスタンスを生成しそれをjava側に渡し,java側で
そのインスタンス(多分Objectとなるのでしょうか)を保持する必要があると
思うのですが,その方法がわかりません.
一般にC++の側で生成したC++のクラスのインスタンスをjava側に受け渡しするには
どのようにしますか
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2003-10-10 10:03
unibon です。こんにちわ。

私は JNI はあまり凝った使い方をした経験はないのですが、
JNI を使う場合は、C++ の都合や制約に Java が従うようにしたほうが、
なにかとトラブルは避けられると感じます。
したがって、バッファ(アロケートしたメモリ領域)は、
Java 側ではなく native 側(C++ 側)で確保したほうが簡単で良いと感じます。

また、Java と C++ 間で、
オブジェクトレベルのものを受け渡すことができるのかどうか分かりませんが、
難しいのではと思います。
私はそのようなことは諦めてしまい、
構造体相当のラッパクラスを、Java 側と C++ 側の両方に用意しておき、
バイト単位のバッファに(一種の)シリアライズ・デシリアライズするメソッドを、
Java 側と C++ 側のそれぞれに備えておき、
あくまでも Java 側と C++ 側との間は、バイトバッファのやりとりにする、
というのが簡単だと思います。
このシリアライズ・デシリアライズもなるべく C++ がやりやすいようにして、
たとえば C++ の struct のメモリイメージをそのまま受け渡すのもアリだと思います。

#目的が、オブジェクト指向を C++ と Java で融合したい、ということならば話は違ってきますが。
Jun
大ベテラン
会議室デビュー日: 2003/08/25
投稿数: 141
投稿日時: 2003-10-10 10:27
ご回答ありがとうございます
引用:

構造体相当のラッパクラスを、Java 側と C++ 側の両方に用意しておき、
バイト単位のバッファに(一種の)シリアライズ・デシリアライズするメソッドを、
Java 側と C++ 側のそれぞれに備えておき、



確かにそのようにすればできるように思いますが保持したいものが相当に容量の大きい
コンテナなのでシリアライズ・デシリアライズの手間が掛かりすぎると考えたのです
もしポインタを保持することができればコンテナのインスタンスではなく
ポインタをjava側に保持することでできそうなのですが,ポインタの保持の方法と
ポインタが有効なのかどうかがなんとなく怪しいように思うのでなやんでいます.
ちいにぃ
大ベテラン
会議室デビュー日: 2002/05/28
投稿数: 244
投稿日時: 2003-10-10 10:49
引用:

C++のコンテナを使う場合ネイティブ側でそのクラスのインスタンスを
生成しそれをjava側に渡し,java側でそのインスタンス(多分Objectと
なるのでしょうか)を保持する必要があると思うのですが,その方法が
わかりません.
一般にC++の側で生成したC++のクラスのインスタンスをjava側に
受け渡しするにはどのようにしますか



「複数のネイティブメソッドをC++インスタンスを保持」したいのですから、
C++インスタンスはヒープから確保し、そのポインタをJava側に渡してやる
わけで。

私が思いついた方法は次の3つです。

方法1 (ポインタをプリミティブ型に入れてやる)
C++→Java:ポインタの値をintやlongに入れて、Java側に返す。
Java→C++:ポインタの値をintやlongで、ネイティブメソッドに渡す。
http://java.sun.com/docs/books/jni/html/stubs.html#30234あたりかな?

方法2 (ハンドルにする)
C++→Java:ポインタをVectorなどのコンテナに入れて、そのインデックスをJavaに返す。
Java→C++:インデックスをネイティブメソッドに渡す。ネイティブメソッド側で
Vectorからポインタを取り出してやる。

方法3 (J2SDK 1.4での拡張機能を使う)
C++→Java:ポインタからNetDirectByteBuffer関数でByteBufferオブジェクトを作り、
Javaに返す。
Java→C++:ByteBufferをネイティブメソッドに渡す。ネイティブメソッド側で
GetDirectBufferAddressでポインタを取り出す。
J2SDK1.4の拡張機能はこちら。http://java.sun.com/j2se/1.4/ja/docs/ja/guide/jni/jni-14.html

[ メッセージ編集済み 編集者: ちいにぃ 編集日時 2003-10-10 14:07 ]
Jun
大ベテラン
会議室デビュー日: 2003/08/25
投稿数: 141
投稿日時: 2003-10-10 13:01
なるほどそのようにしてポインタを保持できるならそれが一番
私にはわかりやすいのでポインタをlongに変換して保持するようにしてみます
1

スキルアップ/キャリアアップ(JOB@IT)