まず、JNA と Java がネイティブ メモリの割り当てを指示する方法についての私の理解はせいぜい本能的なものであり、何が起こっているのかについての私の理解を説明しようとしています。応答に加えて、修正は素晴らしいでしょう...
JNA を使用して Java と C のネイティブ コードを混在させるアプリケーションを実行していますが、Java ガベージ コレクターが直接のネイティブ メモリ割り当てへの参照を解放できず、C ヒープがメモリ不足になるという再現可能な問題が発生しています。
java.nio.ByteBuffer
C コードに a を渡し、バッファを変更してから、Java 関数で結果にアクセスしているため、C アプリケーションが割り当ての問題の原因ではないことは確かです。各関数呼び出し中に単一malloc
と単一の対応がありますが、Java でコードを繰り返し実行した後、malloc は最終的に失敗します。free
これは、問題を示すやや単純化されたコード セットです。実際には、関数呼び出し中に C ヒープに約 16 ~ 32MB を割り当てようとしています。
私のJavaコードは次のようなことをします:
public class MyClass{
public void myfunction(){
ByteBuffer foo = ByteBuffer.allocateDirect(1000000);
MyDirectAccessLib.someOp(foo, 1000000);
System.out.println(foo.get(0));
}
}
public MyDirectAccessLib{
static {
Native.register("libsomelibrary");
}
public static native void someOp(ByteBuffer buf, int size);
}
次に、私のCコードは次のようになります。
#include <stdio.h>
#include <stdlib.h>
void someOp(unsigned char* buf, int size){
unsigned char *foo;
foo = malloc(1000000);
if(!foo){
fprintf(stderr, "Failed to malloc 1000000 bytes of memory\n");
return;
}
free(foo);
buf[0] = 100;
}
問題は、この関数を繰り返し呼び出した後、Java ヒープがある程度安定している (成長が遅い) ことですが、最終的に C 関数はそれ以上メモリを割り当てることができなくなります。大まかに言えば、これは Java が C ヒープにメモリを割り当てているが、Java ByteBuffer オブジェクトが比較的小さいため、このメモリを指す ByteBuffer をクリーンアップしていないためだと思います。
これまでのところ、自分の関数で GC を手動で実行すると、必要なクリーンアップが提供されることがわかりましたが、これはお粗末なアイデアと貧弱なソリューションの両方のようです。
ByteBuffer 領域が適切に解放され、C ヒープ領域が制御されるように、この問題をより適切に管理するにはどうすればよいですか?
問題に対する私の理解は間違っていますか (不適切に実行しているものがありますか)?
編集:実際のアプリケーションをより反映するようにバッファサイズを調整しました。画像には約3000x2000を割り当てています...