1. JNI 调用开销分析
1.1 JNI 调用的隐藏成本
操作类型 | 相对开销 | 原因分析 |
---|---|---|
Java ↔ Native 调用 | 高 | 跨越 VM 边界,上下文切换 |
获取字段/方法 ID | 非常高 | 运行时查找,类似反射 |
创建 Java 对象 | 中 | 触发 GC 可能性 |
基本类型传递 | 极低 | 直接值拷贝 |
引用类型转换 | 中-高 | 内存复制/锁定 |
1.2 性能优化黄金法则
- 减少跨界调用次数:批量处理数据
- 缓存重复使用资源:ID、类引用等
- 选择高效数据通道:直接缓冲区
- 避免不必要转换:最小化数据复制
2. 高效数据传递策略
2.1 数组操作优化
传统方式 (高开销):
jint sum = 0;
for (int i = 0; i < len; i++) {
jint element = env->GetIntArrayElements(array, nullptr)[i];
sum += element;
env->ReleaseIntArrayElements(array, data, JNI_ABORT);
}
优化方案 (批处理):
jint* data = env->GetIntArrayElements(array, nullptr);
jint sum = 0;
for (int i = 0; i < len; i++) {
sum += data[i]; // 单次锁定,多次访问
}
env->ReleaseIntArrayElements(array, data, JNI_ABORT);
临界区访问 (零拷贝):
// 仅当不需要修改数据时使用
const jint* data = env->GetPrimitiveArrayCritical(array, nullptr);
jint sum = 0;
for (int i = 0; i < len; i++) {
sum += data[i];
}
env->ReleasePrimitiveArrayCritical(array, const_cast<jint*>(data), JNI_ABORT);
2.2 使用直接缓冲区 (NIO Buffer)
Java 侧:
// 创建直接缓冲区 (Native 内存)
ByteBuffer buffer = ByteBuffer.allocateDirect(1024 * 1024);
// 传递到 Native
nativeProcessBuffer(buffer);
C++ 侧:
extern "C" void JNICALL
Java_com_example_NativeLib_processBuffer(JNIEnv* env, jobject, jobject buffer) {
// 获取直接内存地址
uint8_t* data = static_cast<uint8_t*>(env->GetDirectBufferAddress(buffer));
jlong capacity = env->GetDirectBufferCapacity(buffer);
// 直接操作内存 (零拷贝)
process_image(data, capacity);
// 注意:不需要释放!
}
优势:
- 避免 Java 堆与 Native 堆间的数据复制
- 支持大规模数据处理 (视频/音频/图像)
- 内存由 Java 管理,自动回收
3. 引用与 ID 缓存策略
3.1 方法/字段 ID 缓存
全局静态缓存 (推荐):
static jclass g_bitmapClass = nullptr;
static jmethodID g_createBitmap = nullptr;
JNIEXPORT void JNICALL
Java_com_example_ImageUtils_init(JNIEnv* env, jclass) {
if (g_bitmapClass == nullptr) {
jclass local = env->FindClass("android/graphics/Bitmap");
g_bitmapClass = static_cast<jclass>(env->NewGlobalRef(local));
env->DeleteLocalRef(local);
}
if (g_createBitmap == nullptr) {
g_createBitmap = env->GetStaticMethodID(g_bitmapClass, "createBitmap",
"(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
}
}
3.2 类引用缓存
初始化时缓存:
// 在 JNI_OnLoad 中全局缓存
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env;
vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
jclass local = env->FindClass("java/nio/ByteBuffer");
g_byteBufferClass = static_cast<jclass>(env->NewGlobalRef(local));
env->DeleteLocalRef(local);
return JNI_VERSION_1_6;
}
4. JNI 注册优化
4.1 静态注册 vs 动态注册
特性 | 静态注册 | 动态注册 |
---|---|---|
注册方式 | 自动 (按命名规则) | 手动 (JNI_OnLoad) |
性能 | 首次调用慢 (按需查找) | 启动时注册 (无查找开销) |
灵活性 | 低 (函数名固定) | 高 (可任意映射) |
混淆影响 | 需保持函数名 | 无影响 |
维护成本 | 低 (IDE 友好) | 高 (手动维护注册表) |
4.2 动态注册示例
// Native 方法实现
void native_method1(JNIEnv* env, jobject) { /* ... */ }
jint native_method2(JNIEnv* env, jobject, jint param) { /* ... */ }
// 方法映射表
static JNINativeMethod methods[] = {
{"nativeMethod1", "()V", reinterpret_cast<void*>(native_method1)},
{"nativeMethod2", "(I)I", reinterpret_cast<void*>(native_method2)}
};
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
JNIEnv* env;
vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
// 注册类方法
jclass clazz = env->FindClass("com/example/NativeClass");
env->RegisterNatives(clazz, methods, sizeof(methods)/sizeof(JNINativeMethod));
env->DeleteLocalRef(clazz);
return JNI_VERSION_1_6;
}
5. 内存管理高级技巧
5.1 局部引用表优化
问题代码 (可能导致溢出):
void process_objects(JNIEnv* env, jobjectArray array) {
jsize len = env->GetArrayLength(array);
for (int i = 0; i < len; i++) {
jobject obj = env->GetObjectArrayElement(array, i);
// 处理对象...
// 忘记删除局部引用!
}
}
优化方案:使用局部帧
void process_objects(JNIEnv* env, jobjectArray array) {
jsize len = env->GetArrayLength(array);
for (int i = 0; i < len; i++) {
env->PushLocalFrame(10); // 创建新局部帧
jobject obj = env->GetObjectArrayElement(array, i);
// 处理对象...
env->PopLocalFrame(nullptr); // 释放当前帧所有局部引用
}
}
5.2 弱引用智能缓存
// 全局弱引用缓存
static jweak g_cachedObject = nullptr;
jobject get_cached_object(JNIEnv* env) {
if (g_cachedObject != nullptr) {
jobject localRef = env->NewLocalRef(g_cachedObject);
if (localRef != nullptr) {
return localRef; // 对象仍存在
}
// 对象已被GC,清除弱引用
env->DeleteWeakGlobalRef(g_cachedObject);
g_cachedObject = nullptr;
}
// 创建新对象并缓存弱引用
jobject newObj = create_new_object(env);
g_cachedObject = env->NewWeakGlobalRef(newObj);
return env->NewLocalRef(newObj);
}
6. 线程池与异步处理
6.1 Native 线程池集成
#include <vector>
#include <thread>
#include <queue>
#include <mutex>
#include <condition_variable>
class ThreadPool {
public:
ThreadPool(size_t threads, JavaVM* jvm) : vm(jvm) {
for(size_t i = 0; i < threads; ++i)
workers.emplace_back([this] { worker_loop(); });
}
void enqueue(std::function<void(JNIEnv*)> task) {
{
std::unique_lock<std::mutex> lock(queue_mutex);
tasks.emplace(std::move(task));
}
condition.notify_one();
}
~ThreadPool() {
stop = true;
condition.notify_all();
for(std::thread &worker: workers)
worker.join();
}
private:
JavaVM* vm;
std::vector<std::thread> workers;
std::queue<std::function<void(JNIEnv*)>> tasks;
std::mutex queue_mutex;
std::condition_variable condition;
bool stop = false;
void worker_loop() {
JNIEnv* env;
vm->AttachCurrentThread(&env, nullptr);
while(!stop) {
std::function<void(JNIEnv*)> task;
{
std::unique_lock<std::mutex> lock(queue_mutex);
condition.wait(lock, [this]{ return stop || !tasks.empty(); });
if(stop && tasks.empty()) break;
task = std::move(tasks.front());
tasks.pop();
}
task(env);
}
vm->DetachCurrentThread();
}
};
// 全局线程池
static ThreadPool* g_pool = nullptr;
// 初始化
extern "C" JNIEXPORT void JNICALL
Java_com_example_NativeLib_initThreadPool(JNIEnv* env, jclass, jint size) {
JavaVM* vm;
env->GetJavaVM(&vm);
g_pool = new ThreadPool(size, vm);
}
// 提交任务
extern "C" JNIEXPORT void JNICALL
Java_com_example_NativeLib_submitTask(JNIEnv* env, jobject, jlong param) {
g_pool->enqueue([param](JNIEnv* env) {
process_task(env, param);
});
}
7. 高级技巧:混合 Java/Native 对象
7.1 在 Native 中保存 Java 对象
class NativeObjectWrapper {
public:
NativeObjectWrapper(JNIEnv* env, jobject obj)
: vm(nullptr), java_ref(nullptr)
{
env->GetJavaVM(&vm);
java_ref = env->NewGlobalRef(obj);
}
virtual ~NativeObjectWrapper() {
if (vm && java_ref) {
JNIEnv* env = get_env();
env->DeleteGlobalRef(java_ref);
}
}
void call_java_method() {
JNIEnv* env = get_env();
jclass cls = env->GetObjectClass(java_ref);
jmethodID mid = env->GetMethodID(cls, "callback", "()V");
env->CallVoidMethod(java_ref, mid);
env->DeleteLocalRef(cls);
}
private:
JavaVM* vm;
jobject java_ref;
JNIEnv* get_env() {
JNIEnv* env = nullptr;
vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
return env;
}
};
// 从 Java 创建 Native 对象
extern "C" JNIEXPORT jlong JNICALL
Java_com_example_NativeObject_createNative(JNIEnv* env, jobject obj) {
auto* wrapper = new NativeObjectWrapper(env, obj);
return reinterpret_cast<jlong>(wrapper);
}
// 调用 Native 对象方法
extern "C" JNIEXPORT void JNICALL
Java_com_example_NativeObject_callNative(JNIEnv* env, jobject, jlong ptr) {
auto* wrapper = reinterpret_cast<NativeObjectWrapper*>(ptr);
wrapper->call_java_method();
}
// 销毁 Native 对象
extern "C" JNIEXPORT void JNICALL
Java_com_example_NativeObject_destroyNative(JNIEnv* env, jobject, jlong ptr) {
delete reinterpret_cast<NativeObjectWrapper*>(ptr);
}