標籤:android art
ART的初始化
下面我們從JNI_GetDefaultJavaVMInitArgs(),JNI_CreateJavaVM()和JNI_GetCreatedJavaVMs()三個函數入手來瞭解ART的初始化過程。這三個函數的代碼位於jni_internal.cc中。
JNI_GetDefaultJavaVMInitArgs()函數在ART中沒有作為,只是返回JNI_ERR。如下所示:
extern "C" jintJNI_GetDefaultJavaVMInitArgs(void* ) {
return JNI_ERR;
}
JNI_GetCreatedJavaVMs()函數用來返回在Runtime中儲存的JavaVMExt的指標,函數代碼如下所示:
extern "C" jint JNI_GetCreatedJavaVMs(JavaVM**vms, jsize, jsize* vm_count) {
Runtime* runtime =Runtime::Current();
if (runtime == NULL) {
*vm_count = 0;
} else {
*vm_count = 1;
vms[0] = runtime->GetJavaVM();
}
return JNI_OK;
}
Runtime的GetJavaVM()函數只是返回了Runtime類的成員變數java_vm_,如下所示。
JavaVMExt* GetJavaVM() const {
return java_vm_;
}
java_vm_是JavaVMExt類型的指標,定義如下:
JavaVMExt* java_vm_;
理解了兩個簡單的函數後,我們再來分析JNI_CreateJavaVM()函數,代碼如下:
extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm,JNIEnv** p_env, void* vm_args) {
const JavaVMInitArgs* args =static_cast(vm_args);
// 檢查JNI的版本
if(IsBadJniVersion(args->version)) {
LOG(ERROR) << "Bad JNI version passed to CreateJavaVM: "<< args->version;
return JNI_EVERSION;
}
// 儲存啟動參數到options中。
Runtime::Optionsoptions;
for (int i = 0; i <args->nOptions; ++i) {
JavaVMOption* option = &args->options[i];
options.push_back(std::make_pair(std::string(option->optionString),option->extraInfo));
}
bool ignore_unrecognized =args->ignoreUnrecognized;
if (!Runtime::Create(options,ignore_unrecognized)) { // 建立虛擬機器
return JNI_ERR;
}
Runtime* runtime =Runtime::Current();
bool started =runtime->Start(); //啟動虛擬機器
if (!started) {
delete Thread::Current()->GetJniEnv();
delete runtime->GetJavaVM();
return JNI_ERR; // 啟動失敗,方法
}
*p_env =Thread::Current()->GetJniEnv();
*p_vm =runtime->GetJavaVM();
return JNI_OK;
}
JNI_CreateJavaVM()函數中調用Runtime的Create()函數來建立虛擬機器,然後調用start()函數來啟動它。在ART中,Runtime對象的地位和Dalvik中的DvmGlobals對象gDVm類似,包含了所有重要的變數。
下面我們繼續分析Create()函數:
bool Runtime::Create(const Options& options,bool ignore_unrecognized) {
if (Runtime::instance_ !=NULL) {
return false; //只能建立一個Runtime執行個體
}
InitLogging(NULL); // Calls Locks::Init() as aside effect.
instance_ = newRuntime; // 建立了Runtime類的執行個體
if(!instance_->Init(options, ignore_unrecognized)){ // 初始化Runtime對象
delete instance_;
instance_ = NULL;
return false;
}
return true;
}
Runtime的Create()函數中建立了Runtime對象,並調用它的Init()函數進行初始化。函數代碼如下:
bool Runtime::Init(const Options&raw_options, bool ignore_unrecognized) {
UniquePtroptions(ParsedOptions::Create(raw_options,
ignore_unrecognized));
......
QuasiAtomic::Startup();
Monitor::Init(options->lock_profiling_threshold_,
options->hook_is_sensitive_thread_);
host_prefix_ =options->host_prefix_;
boot_class_path_string_ =options->boot_class_path_string_;
... // 更多的賦值語句
monitor_list_ = newMonitorList;
thread_list_ = newThreadList;
intern_table_ = newInternTable;
if(options->interpreter_only_) {
GetInstrumentation()->ForceInterpretOnly();
}
// 建立堆(Heap)對象
heap_ = newgc::Heap(options->heap_initial_size_,
options->heap_growth_limit_,
......);
BlockSignals();
InitPlatformSignalHandlers();
// 建立JavaVMExt對象
java_vm_ = new JavaVMExt(this,options.get());
// 將當前的主線程變成一個“Java” 線程
Thread::Startup();
Thread* self =Thread::Attach("main", false, NULL, false);
self->TransitionFromSuspendedToRunnable();
GetHeap()->EnableObjectValidation();
if(GetHeap()->GetContinuousSpaces()[0]->IsImageSpace()) {
class_linker_ = ClassLinker::CreateFromImage(intern_table_);
} else {
class_linker_ =ClassLinker::CreateFromCompiler(*options->boot_class_path_, intern_table_);
}
......
return true;
}
Init()函數最重要的工作是建立了Heap對象和ClassLinker對象。我們只要將ART和Dalvik對比一下就可以理解,因為ART模式下並不需要去解析和執行位元組碼,所以它的工作比Dalivk要少很多。即使應用已經編譯成了可執行代碼,但是同樣也要支援記憶體回收功能,所以Heap模組還是必不可少的。Art的Heap模組的功能幾乎和Dalvik中的相同,記憶體回收的演算法也是標誌並清除法,不過代碼的實現更加晦澀,所以本書不打算再分析一遍Art的Heap演算法了。
ART雖然不用去裝載和執行位元組碼,但是還是要保留所有Java類的資訊,Java程式和C++程式除了記憶體管理方式不同外,最大的區別是Java程式能夠動態擷取各種類的資訊,包括方法,變數等。所以ART中同樣也要提供這些功能,否則編譯出來的程式也無法使用。ClassLinker類的作用就是在ART內部提供各種Java類的解析功能。
ART開始運行
初始化完成之後,接下來是調用Runtime的start()函數開始運行,函數代碼如下:
bool Runtime::Start() {
VLOG(startup) <<"Runtime::Start entering";
Thread* self =Thread::Current();
self->TransitionFromRunnableToSuspended(kNative);
started_ = true;
InitNativeMethods() //初始化本地的JNI方法
InitThreadGroups(self);
Thread::FinishStartup();
if (is_zygote_) {
if (!InitZygote()) {
return false;
}
} else {
DidForkFromZygote();
}
StartDaemonThreads(); //調用java.lang.Daemons的start方法
system_class_loader_ =CreateSystemClassLoader(); //建立一個ClassLoader對象
self->GetJniEnv()->locals.AssertEmpty();
VLOG(startup) <<"Runtime::Start exiting";
finished_starting_ =true;
return true;
}
Start()方法中會調用InitNativeMethods()來初始化本地的JNI方法,ART中也同樣支援JNI函數,不過ART中對部分系統的JNI函數進行了重寫,但是實現原理和Dalvik中的沒有太大區別,而大部分其他模組的JNI函數還是保持不變。調用InitNativeMethods()方法後這些JNI函數就可以使用了。
接下來如果是在Zygote進程中,則會調用InitZygote()函數來進行初始化,這個函數的實現和Dalvik中的幾乎一樣,主要工作是設定進程的groupid,以及mountrootfs檔案系統到根目錄。如果不是Zygote進程,則調用DidForkFromZygote()函數,這個函數主要工作是調用Heap對象的CreateThreadPool()函數來建立線程池。
最後Start()函數中調用了StartDaemonThreads()函數,這個函數的工作是調用Java類Daemons的start()方法來啟動一些Deamon線程,這些Deamon前面我們已經分析過了。這個過程實際上和Dalvik啟動時完成的最後一項工作相同。
對比Dalivk啟動時需要完成的工作,ART是相當的簡單了。