本文基于Android10的classlinker的源碼,分析了linker對于class加載是怎么保證并發安全的。
簡化DefineClass流程
ObjPtr<mirror::Class> ClassLinker::DefineClass() {
auto klass = hs.NewHandle<mirror::Class>(nullptr);
//分配一個Class的空間
klass.Assign(AllocClass(self, SizeOfClassWithoutEmbeddedTables(dex_file, dex_class_def)));
//注冊dex file,這一步不會重復注冊,就不再分析了
ObjPtr<mirror::DexCache> dex_cache = RegisterDexFile(*new_dex_file, class_loader.Get());
//對klass加鎖
ObjectLock<mirror::Class> lock(self, klass);
//安裝class,把class的基本信息設置好
SetupClass(*new_dex_file, *new_class_def, klass, class_loader.Get());
//注冊到ClassTable,后續就可以直接從table里面找了
ObjPtr<mirror::Class> existing = InsertClass(descriptor, klass.Get(), hash);
if (existing != nullptr) {
// We failed to insert because we raced with another thread. Calling EnsureResolved may cause
// this thread to block.
return EnsureResolved(self, descriptor, existing);
}
//加載
LoadClass();
//鏈接
LinkClass();
//...
}
重點一、InsertClass
InsertClass函數
重點二、EnsureResolved
InsertClass()執行結束之后,klass還會經過加載、鏈接、初始化流程,如何確保最終返回的class經過了這些流程呢?
根據重點一,可知DefineClass()
方法中的ObjectLock<mirror::Class> lock(self, klass)
同樣會持有klass的鎖直到DefineClass方法的結束。而EnsureResolved恰好利用了這一點,讓其它線程通過競爭klass鎖的方式,確保klass的Define流程結束:
EnsureResolved關鍵代碼