gpt4 book ai didi

java - JNI - 来自 C++ 的免费 ByteBuffer

转载 作者:搜寻专家 更新时间:2023-11-01 02:28:45 48 4
gpt4 key购买 nike

总结

  1. 使用 ByteBuffer.allocateDirect(someBufferSize) 在 Java 中创建称为缓冲区的 ByteBuffer
  2. 用数据填充缓冲区
  3. 将缓冲区作为 jobject - jbuffer 传递给 C++
  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 - 在 native 端)并且必须被释放,否则我会得到 OutOfMemory 错误。

最佳答案

您不需要释放缓冲区。您已经在 J​​ava 端分配了它,这意味着它是 JVM 对象,GC 会处理它。与在 C 端分配相反,因此是 GC 不知道的 native 对象。您甚至不需要执行 DeleteLocalRef,因为在从 native 方法返回时,JNI 机器会为您删除所有本地引用。仅当在一个 native 调用的范围内有数百个 JNI 调用返回 JVM 时,您才需要显式删除,因此您甚至在返回 JVM 之前就会用完句柄。

我必须承认我不确切知道 GC 是如何知道它不应该触及您的 ByteBuffer 的,但我猜想通过调用 GetObjectField 您会增加 ByteBuffer 上的引用计数并减少删除本地引用。所以在这两个 JNI 调用之间,ByteBuffer 是安全的。

关于java - JNI - 来自 C++ 的免费 ByteBuffer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14751527/

48 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com