JNI官网:
https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/jniTOC.html
本文以7.2 之前的源码分析JNI方法调用及对IndirectReferenceTable操作。8.0代码有变动。
NDK开发时,native调用java方法是通过ENV获取函数指针数组,完成调用,env方法的实现在 jni_internal.cc中。
以 CallObjectMethod为例,
IndirectReferenceTable.add
ProfileSaver::FetchAndCacheResolvedClassesAndMethods(
1 JNI 方法调用
jni_internal.cc
static jobject CallObjectMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
676 va_list ap;
677 va_start(ap, mid);
678 CHECK_NON_NULL_ARGUMENT(obj);
679 CHECK_NON_NULL_ARGUMENT(mid);
680 ScopedObjectAccess soa(env);
681 JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
682 va_end(ap);
683 return soa.AddLocalReference<jobject>(result.GetL() //每次调用添加本地索引表
684 }
1.1 JNIEnvExt::AddLocalReference
/art/runtime/jni_env_ext-inl.h
24namespace art {
25
26template<typename T>
27inline T JNIEnvExt::AddLocalReference(mirror::Object* obj) {
28 IndirectRef ref = locals.Add(local_ref_cookie, obj);//添加到表单
29
30 // TODO: fix this to understand PushLocalFrame, so we can turn it on.
31 if (false) {
32 if (check_jni) {
33 size_t entry_count = locals.Capacity();
34 if (entry_count > 16) {
35 locals.Dump(LOG(WARNING) << "Warning: more than 16 JNI local references: "
36 << entry_count << " (most recent was a " << PrettyTypeOf(obj) << ")\n");
37 // TODO: LOG(FATAL) in a later release?
38 }
39 }
40 }
41
42 return reinterpret_cast<T>(ref);
43}
44
45}
1.2 locals 是IndirectReferenceTable实例
/art/runtime/indirect_reference_table.cc
105IndirectRef IndirectReferenceTable::Add(uint32_t cookie, mirror::Object* obj) {
106 IRTSegmentState prevState;
107 prevState.all = cookie;
108 size_t topIndex = segment_state_.parts.topIndex;
109
110 CHECK(obj != nullptr);
111 VerifyObject(obj);
112 DCHECK(table_ != nullptr);
113 DCHECK_GE(segment_state_.parts.numHoles, prevState.parts.numHoles);
114
115 if (topIndex == max_entries_) {
116 LOG(FATAL) << "JNI ERROR (app bug): " << kind_ << " table overflow "
117 << "(max=" << max_entries_ << ")\n"
118 << MutatorLockedDumpable<IndirectReferenceTable>(*this);
119 }
120
121 // We know there's enough room in the table. Now we just need to find
122 // the right spot. If there's a hole, find it and fill it; otherwise,
123 // add to the end of the list.
124 IndirectRef result;
125 int numHoles = segment_state_.parts.numHoles - prevState.parts.numHoles;
126 size_t index;
127 if (numHoles > 0) {
128 DCHECK_GT(topIndex, 1U);
129 // Find the first hole; likely to be near the end of the list.
130 IrtEntry* pScan = &table_[topIndex - 1];
131 DCHECK(!pScan->GetReference()->IsNull());
132 --pScan;
133 while (!pScan->GetReference()->IsNull()) {
134 DCHECK_GE(pScan, table_ + prevState.parts.topIndex);
135 --pScan;
136 }
137 index = pScan - table_;
138 segment_state_.parts.numHoles--;
139 } else {
140 // Add to the end.
141 index = topIndex++;
142 segment_state_.parts.topIndex = topIndex;
143 }
144 table_[index].Add(obj); //添加到表单中
145 result = ToIndirectRef(index);
146 if ((false)) {
147 LOG(INFO) << "+++ added at " << ExtractIndex(result) << " top=" << segment_state_.parts.topIndex
148 << " holes=" << segment_state_.parts.numHoles;
149 }
150
151 DCHECK(result != nullptr);
152 return result;
153}
table_ 数据表的结构:
385 // Mem map where we store the indirect refs.
386 std::unique_ptr<MemMap> table_mem_map_;
387 // bottom of the stack. Do not directly access the object references
388 // in this as they are roots. Use Get() that has a read barrier.
389 IrtEntry* table_; 结构
390 /* bit mask, ORed into all irefs */
391 const IndirectRefKind kind_;
392 /* max #of entries allowed */
393 const size_t max_entries_;
表的初始化:
IndirectReferenceTable::IndirectReferenceTable(size_t initialCount,
71 size_t maxCount, IndirectRefKind desiredKind,
72 bool abort_on_error)
73 : kind_(desiredKind),
74 max_entries_(maxCount) {
75 CHECK_GT(initialCount, 0U);
76 CHECK_LE(initialCount, maxCount);
77 CHECK_NE(desiredKind, kHandleScopeOrInvalid);
78
79 std::string error_str;
80 const size_t table_bytes = maxCount * sizeof(IrtEntry);
81 table_mem_map_.reset(MemMap::MapAnonymous("indirect ref table", nullptr, table_bytes,
82 PROT_READ | PROT_WRITE, false, false, &error_str));
83 if (abort_on_error) {
84 CHECK(table_mem_map_.get() != nullptr) << error_str;
85 CHECK_EQ(table_mem_map_->Size(), table_bytes);
86 CHECK(table_mem_map_->Begin() != nullptr);
87 } else if (table_mem_map_.get() == nullptr ||
88 table_mem_map_->Size() != table_bytes ||
89 table_mem_map_->Begin() == nullptr) {
90 table_mem_map_.reset();
91 LOG(ERROR) << error_str;
92 return;
93 }
94 table_ = reinterpret_cast<IrtEntry*>(table_mem_map_->Begin());//初始化
95 segment_state_.all = IRT_FIRST_SEGMENT;
96}
定义处:/art/runtime/jni_env_ext.h
// JNI local references.
67 IndirectReferenceTable locals GUARDED_BY(Locks::mutator_lock_);
68
初始化:
6JNIEnvExt::JNIEnvExt(Thread* self_in, JavaVMExt* vm_in)
57 : self(self_in),
58 vm(vm_in),
59 local_ref_cookie(IRT_FIRST_SEGMENT),
60 locals(kLocalsInitial, kLocalsMax, kLocal, false), //初始化
61 check_jni(false),
62 runtime_deleted(false),
63 critical(0),
64 monitors("monitors", kMonitorsInitial, kMonitorsMax) {
65 functions = unchecked_functions = GetJniNativeInterface();
66 if (vm->IsCheckJniEnabled()) {
67 SetCheckJniEnabled(true);
68 }
69}
static constexpr size_t kLocalsInitial = 64; // Arbitrary.
最大值:
32// Maximum number of local references in the indirect reference table. The value is arbitrary but
33// low enough that it forces sanity checks.
34static constexpr size_t kLocalsMax = 512;
3 什么时候remove?
函数原型:
// Removes an object. We extract the table offset bits from "iref"
166// and zap the corresponding entry, leaving a hole if it's not at the top.
167// If the entry is not between the current top index and the bottom index
168// specified by the cookie, we don't remove anything. This is the behavior
169// required by JNI's DeleteLocalRef function.
170// This method is not called when a local frame is popped; this is only used
171// for explicit single removals.
172// Returns "false" if nothing was removed.
173bool IndirectReferenceTable::Remove(uint32_t cookie, IndirectRef iref) {
174 IRTSegmentState prevState;
175 prevState.all = cookie;
176 int topIndex = segment_state_.parts.topIndex;
177 int bottomIndex = prevState.parts.topIndex;
178
179 DCHECK(table_ != nullptr);
180 DCHECK_GE(segment_state_.parts.numHoles, prevState.parts.numHoles);
181
182 if (GetIndirectRefKind(iref) == kHandleScopeOrInvalid) {
183 auto* self = Thread::Current();
184 if (self->HandleScopeContains(reinterpret_cast<jobject>(iref))) {
185 auto* env = self->GetJniEnv();
186 DCHECK(env != nullptr);
187 if (env->check_jni) {
188 ScopedObjectAccess soa(self);
189 LOG(WARNING) << "Attempt to remove non-JNI local reference, dumping thread";
190 if (kDumpStackOnNonLocalReference) {
191 self->Dump(LOG(WARNING));
192 }
193 }
194 return true;
195 }
196 }
调用处:
void JNIEnvExt::DeleteLocalRef(jobject obj) {
87 if (obj != nullptr) {
88 locals.Remove(local_ref_cookie, reinterpret_cast<IndirectRef>(obj));
89 }
90}
只有在删除Local是才会清除表单:
B 全局索引表
globals_
// Not guarded by globals_lock since we sometimes use SynchronizedGet in Thread::DecodeJObject.
198 IndirectReferenceTable globals_;
static jobject NewGlobalRef(JNIEnv* env, jobject obj) {
519 ScopedObjectAccess soa(env);
520 mirror::Object* decoded_obj = soa.Decode<mirror::Object*>(obj);
521 return soa.Vm()->AddGlobalRef(soa.Self(), decoded_obj);
522 }
初始化:
/art/runtime/java_vm_ext.cc
423JavaVMExt::JavaVMExt(Runtime* runtime, const RuntimeArgumentMap& runtime_options)
424 : runtime_(runtime),
425 check_jni_abort_hook_(nullptr),
426 check_jni_abort_hook_data_(nullptr),
427 check_jni_(false), // Initialized properly in the constructor body below.
428 force_copy_(runtime_options.Exists(RuntimeArgumentMap::JniOptsForceCopy)),
429 tracing_enabled_(runtime_options.Exists(RuntimeArgumentMap::JniTrace)
430 || VLOG_IS_ON(third_party_jni)),
431 trace_(runtime_options.GetOrDefault(RuntimeArgumentMap::JniTrace)),
432 globals_lock_("JNI global reference table lock"),
433 globals_(gGlobalsInitial, gGlobalsMax, kGlobal),
434 libraries_(new Libraries),
435 unchecked_functions_(&gJniInvokeInterface),
436 weak_globals_lock_("JNI weak global reference table lock", kJniWeakGlobalsLock),
437 weak_globals_(kWeakGlobalsInitial, kWeakGlobalsMax, kWeakGlobal),
438 allow_accessing_weak_globals_(true),
439 weak_globals_add_condition_("weak globals add condition", weak_globals_lock_) {
440 functions = unchecked_functions_;
441 SetCheckJniEnabled(runtime_options.Exists(RuntimeArgumentMap::CheckJni));
442}
最大值:
45static size_t gGlobalsInitial = 512; // Arbitrary.
46static size_t gGlobalsMax = 51200; // Arbitrary sanity check. (Must fit in 16 bits.)