4

概要

  1. ByteBuffer.allocateDirect(someBufferSize) で buffer と呼ばれる Java で ByteBuffer を作成します。
  2. バッファをデータで埋める
  3. バッファを C++ に jobject として渡す - jbuffer
  4. env->GetDirectBufferAddress(jbuffer) でバッファダイレクトポインタを取得
  5. C++ 側でバッファ データを操作します。GC がバッファーをクリーンアップしないようにするにはどうすればよいでしょうか?
  6. 作業は完了しました - 今は jbuffer は必要ありません。
  7. jbuffer を解放しますか? free(jbuffer) - 無効なアドレス エラーが発生します

長い部分

次のコードを使用して Java AssetManager で PNG ファイルを読み込み、Open GL ES 2.0 テクスチャの作成に使用します。

Java側のPNGクラス

import java.nio.ByteBuffer;
import android.graphics.Bitmap;

public class PNG 
{
 private static final int BYTES_PER_PIXEL_PNG = 4;
 private static final String LOG_TAG = "[PNG]";
 public int width;
 public int height;
 public ByteBuffer pixels;


 public PNG(Bitmap bitmap)
 {
  this.width = bitmap.getWidth();
  this.height = bitmap.getHeight();
  this.pixels = ByteBuffer.allocateDirect(this.width * this.height * BYTES_PER_PIXEL_PNG);
  bitmap.copyPixelsToBuffer(this.pixels);
 }
}

public static PNG loadPNG(String path)
{
    InputStream is = null;
    try
    {
        is = ASSETS_MANAGER.open(path);//get png file stream with AssetsManager instance
    }
    catch (IOException e)
    {
        Log.e(LOG_TAG, "Can't load png - " + path, e);
    }

    return new PNG(BitmapFactory.decodeStream(is));
}

C++ 側の PNG

typedef struct png
{
int width;
int height;
char* pixels;
} png;

png* load_png(const char* path)
{
 png* res = (res*) malloc(sizeof(png);
 ...
 jobject _png = env->CallStaticObjectMethod(get_java_lib_class(), get_method_id(JAVA_LIB_LOAD_PNG, JAVA_LIB_LOAD_PNG_SIGN), _path);//Calling loadPng() from Java, get PNG jobject
 jobject _pixels =  env->GetObjectField(_png, PNG_FIELDS->PNG_PIXELS_ID);//Getting pixels field from Java PNG jobject
 res->pixels = (char*) env->GetDirectBufferAddress(_pixels);//Get direct pointer to our pixel data
 //Cleanup
 ...
 env->DeleteLocalRef(_png);
 env->DeleteLocalRef(_pixels);
 return res;
}

次に、pngを使用してテクスチャを作成します

void test_create_tex(const char* path)
{
 ...
 png* source = load_png(path);
 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, source->width, source->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, source->pixels);
//We don't need source pixel data any more
//free(source->pixels);//INVALID HEAP ADDRESS (deadbaad)
free(source);
}

では、直接ポインタを使用して C++ 側で使用した後、バイト バッファを解放するにはどうすればよいでしょうか。それは直接割り当てられ(mallocのように-ネイティブ側で)、解放する必要があります。そうしないと、OutOfMemoryエラーが発生します。

4

2 に答える 2

4

バッファを解放する必要はありません。Java側で割り当てました。つまり、JVMオブジェクトであり、GCがそれを処理します。C側での割り当てとは対照的に、GCが認識しないネイティブオブジェクトです。DeleteLocalRefネイティブメソッドから戻ると、JNI機構によってすべてのローカル参照が削除されるため、これを行う必要はありません。1つのネイティブ呼び出しのスコープ内でJVMに戻るJNI呼び出しが数百ある場合にのみ明示的に削除する必要があるため、JVMに戻る前でもハンドルが不足します。

GCがByteBufferに触れてはならないことをどのように知っているのか正確にはわからないことを認めなければなりませんが、呼び出しGetObjectFieldてByteBufferのrefcountをインクリメントし、でデクリメントしていると思いますDeleteLocalRef。したがって、これら2つのJNI呼び出しの間、ByteBufferは安全にとどまることができます。

于 2013-02-11T14:21:58.413 に答える
2

私の意見では、 のリリースについて心配する必要はありませんByteBuffer pixels。JVM によって管理されているからです。本当に気をつけなければならないのは、C++ で使用されるときにガベージ コレクションが行われないようにすることです。

于 2013-02-07T12:58:57.310 に答える