在 ART(Android Runtime)虚拟机中,HandleScope 和 LocalReferenceTable 都是用于管理 JNI(Java Native Interface)引用的重要机制。
1. HandleScope
作用:
HandleScope 是一个基于栈的对象引用管理机制,用于管理局部引用(local references)。它将 Java 对象(jobject)存储在栈上,并自动处理这些引用的生命周期。
特点:
- 基于栈:
HandleScope是在栈上分配的,因此它的生命周期受限于当前函数的执行范围。当函数返回时,HandleScope会自动析构,并释放其中存储的对象引用。 - 自动管理生命周期:由于它是基于栈的,当作用域完毕,
HandleScope会自动销毁,不需要手动释放引用的内存。 - 高效:因为是在栈上操作,通常比堆分配的局部引用(如
env->NewLocalRef)更高效。 - 适用于短生命周期的引用:通常用于那些只在函数内部使用,并且生命周期不超过函数执行范围的对象引用。
示例代码:
void ExampleFunction(JNIEnv* env, jobject obj) {
StackHandleScope<jobject> hs(env);
jobject managed_obj = hs.NewHandle(obj);
// 使用 managed_obj
}
在上面的代码中,managed_obj 是一个在 StackHandleScope 中创建的句柄,它的生命周期由 StackHandleScope 管理,当函数执行完毕,StackHandleScope 析构,managed_obj 也自动失效。
2. LocalReferenceTable
作用:
LocalReferenceTable 是 ART 虚拟机中用于管理局部引用表的结构。它是一个更底层的机制,用于存储和管理所有通过 JNI 环境(JNIEnv)创建的局部引用。
特点:
- 堆上管理:
LocalReferenceTable是在堆上分配的,用于存储通过NewLocalRef、FindClass、NewObject等 JNI 函数创建的局部引用。 -
//分配代码 LrtEntry* SmallLrtAllocator::Allocate(size_t size, std::string* error_msg) { size_t index = GetIndex(size); MutexLock lock(Thread::Current(), lock_); size_t fill_from = index; while (fill_from != num_lrt_slots_ && free_lists_[fill_from] == nullptr) { ++fill_from; } void* result = nullptr; if (fill_from != num_lrt_slots_) { // We found a slot with enough memory. result = free_lists_[fill_from]; free_lists_[fill_from] = *reinterpret_cast<void**>(result); } else { // We need to allocate a new page and split it into smaller pieces. MemMap map = NewLRTMap(gPageSize, error_msg); if (!map.IsValid()) { return nullptr; } result = map.Begin(); shared_lrt_maps_.emplace_back(std::move(map)); } while (fill_from != index) { --fill_from; // Store the second half of the current buffer in appropriate free list slot. void* mid = reinterpret_cast<uint8_t*>(result) + (kInitialLrtBytes << fill_from); DCHECK(free_lists_[fill_from] == nullptr); *reinterpret_cast<void**>(mid) = nullptr; free_lists_[fill_from] = mid; } // Clear the memory we return to the caller. std::memset(result, 0, kInitialLrtBytes << index); return reinterpret_cast<LrtEntry*>(result); } - 手动管理生命周期:局部引用通过
LocalReferenceTable管理,开发者可以手动调用DeleteLocalRef来释放这些引用或者作用域结束自动释放
示例代码:
void ExampleFunction(JNIEnv* env, jobject obj) {
jobject localRef = env->NewLocalRef(obj);
if (localRef != nullptr) {
// 使用 localRef
env->DeleteLocalRef(localRef); // 手动删除局部引用
}
}
在上面的代码中,localRef 是一个通过 NewLocalRef 创建的局部引用
区别总结
| 特性 | HandleScope | LocalReferenceTable |
|---|---|---|
| 存储位置 | 基于栈的对象引用管理 | 堆上的局部引用表 |
| 生命周期管理 | 自动管理,函数返回时自动销毁 | 自动或手动 |
| 适用场景 | 适用于短生命周期的对象引用,通常在函数内部使用 | 适用于短生命周期的对象引用,通常在函数内部使用 |
| 效率 | 更高效,因为基于栈 | 相对较低效,在堆上分配 |
| 释放时机 | 函数执行完毕时自动释放 | 手动释放或者函数执行完毕时自动释放 |
| 全局管理 | 不需要全局管理,只在当前函数范围内有效 | 不需要全局管理,只在当前函数范围内有效 |
总结
HandleScope 和 LocalReferenceTable 的主要区别在于它们的管理方式和适用场景。HandleScope 在栈上分配,效率更高,空间有限,但无法删除单个引用
LocalReferenceTable 在堆上分配,空间较大但效率较低,可单独管理对象引用
1543

被折叠的 条评论
为什么被折叠?



