浅析ART虚拟机(二)虚拟机创建

前言

上一篇说到了在启动zygote的时候,会启动art虚拟机,并且已经到了虚拟机的JNI_CreateJavaVM函数入口处。我们接着往下分析。

ART中的JNI_CreateJavaVM

源代码在ART虚拟机中的java_vm_ext.cc中

// JNI Invocation interface.

extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
  ScopedTrace trace(__FUNCTION__);
  const JavaVMInitArgs* args = static_cast<JavaVMInitArgs*>(vm_args);
  if (JavaVMExt::IsBadJniVersion(args->version)) {
    LOG(ERROR) << "Bad JNI version passed to CreateJavaVM: " << args->version;
    return JNI_EVERSION;
  }
  RuntimeOptions options;
  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;
  }

  // Initialize native loader. This step makes sure we have
  // everything set up before we start using JNI.
  android::InitializeNativeLoader();

  Runtime* runtime = Runtime::Current(); //创建当前的runtime
  bool started = runtime->Start(); // 启动
  if (!started) {
    delete Thread::Current()->GetJniEnv();
    delete runtime->GetJavaVM();
    LOG(WARNING) << "CreateJavaVM failed";
    return JNI_ERR;
  }

  *p_env = Thread::Current()->GetJniEnv();
  *p_vm = runtime->GetJavaVM();
  return JNI_OK;
}

此时可以看到,通过runtime进行初始化,然后进行start完成虚拟机的创建。这一块的逻辑比较复杂,可以先来一张图整理一下。流程如图: img

Runtime()->Create()

bool Runtime::Create(RuntimeArgumentMap&& runtime_options) {
...
  instance_ = new Runtime;
  Locks::SetClientCallback(IsSafeToCallAbort);
  if (!instance_->Init(std::move(runtime_options))) {
    instance_ = nullptr;
    return false;
  }
  return true;
}

创建runtime的过程中,需要进行init操作

Runtime()->init()
bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
  ...
  // 获取各种启动参数
  // 获取到默认的栈大小
  default_stack_size_ = runtime_options.GetOrDefault(Opt::StackSize);
  //创建堆空间
    heap_ = new gc::Heap(runtime_options.GetOrDefault(Opt::MemoryInitialSize),
                       runtime_options.GetOrDefault(Opt::HeapGrowthLimit),
                       runtime_options.GetOrDefault(Opt::HeapMinFree),
                       runtime_options.GetOrDefault(Opt::HeapMaxFree),
                       runtime_options.GetOrDefault(Opt::HeapTargetUtilization),
                       foreground_heap_growth_multiplier,
                       runtime_options.GetOrDefault(Opt::MemoryMaximumSize),
                       runtime_options.GetOrDefault(Opt::NonMovingSpaceCapacity),
                       GetBootClassPath(),
                       GetBootClassPathLocations(),
                       image_location_,
                       instruction_set_,
                       // Override the collector type to CC if the read barrier config.
                       kUseReadBarrier ? gc::kCollectorTypeCC : xgc_option.collector_type_,
                       kUseReadBarrier ? BackgroundGcOption(gc::kCollectorTypeCCBackground)
                                       : runtime_options.GetOrDefault(Opt::BackgroundGc),
                       runtime_options.GetOrDefault(Opt::LargeObjectSpace),
                       runtime_options.GetOrDefault(Opt::LargeObjectThreshold),
                       runtime_options.GetOrDefault(Opt::ParallelGCThreads),
                       runtime_options.GetOrDefault(Opt::ConcGCThreads),
                       runtime_options.Exists(Opt::LowMemoryMode),
                       runtime_options.GetOrDefault(Opt::LongPauseLogThreshold),
                       runtime_options.GetOrDefault(Opt::LongGCLogThreshold),
                       runtime_options.Exists(Opt::IgnoreMaxFootprint),
                       runtime_options.GetOrDefault(Opt::UseTLAB),
                       xgc_option.verify_pre_gc_heap_,
                       xgc_option.verify_pre_sweeping_heap_,
                       xgc_option.verify_post_gc_heap_,
                       xgc_option.verify_pre_gc_rosalloc_,
                       xgc_option.verify_pre_sweeping_rosalloc_,
                       xgc_option.verify_post_gc_rosalloc_,
                       xgc_option.gcstress_,
                       xgc_option.measure_,
                       runtime_options.GetOrDefault(Opt::EnableHSpaceCompactForOOM),
                       use_generational_cc,
                       runtime_options.GetOrDefault(Opt::HSpaceCompactForOOMMinIntervalsMs),
                       runtime_options.Exists(Opt::DumpRegionInfoBeforeGC),
                       runtime_options.Exists(Opt::DumpRegionInfoAfterGC),
                       image_space_loading_order_);
    // 标记线程为启动状态
    Thread::Startup(); 
    // 设置当前线程为虚拟机的主线程
    Thread* self = Thread::Attach("main", false, nullptr, false);
    {
        // 通过dlopen加载native bridge
        std::string native_bridge_file_name = runtime_options.ReleaseOrDefault(Opt::NativeBridge);
        is_native_bridge_loaded_ = LoadNativeBridge(native_bridge_file_name);
    }
}

其中比较关键的堆的操作,我们放到后面来进行分析。 现在我们继续关注虚拟机启动的流程。

android::INitializeNativeLoader

void InitializeNativeLoader() {
#if defined(__ANDROID__)
  std::lock_guard<std::mutex> guard(g_namespaces_mutex);
  g_namespaces->Initialize();
#endif
}

Runtime()->start()

bool Runtime::Start() {
  {
    ScopedTrace trace2("InitNativeMethods");
    // 初始化native方法
    InitNativeMethods();
  }
  // 完成初始化
  Thread::FinishStartup();
  // 创建系统类加载器
  system_class_loader_ = CreateSystemClassLoader(this);
  // 创建守护进程
  StartDaemonThreads();
}
StartDewmonThreads
void Runtime::StartDaemonThreads() {
    // 获取到java/lang/daemon,并且调用start方法。
  JNIEnv* env = self->GetJniEnv();
  env->CallStaticVoidMethod(WellKnownClasses::java_lang_Daemons,
                            WellKnownClasses::java_lang_Daemons_start);
}
    private static final Daemon[] DAEMONS = new Daemon[] {
            HeapTaskDaemon.INSTANCE,
            ReferenceQueueDaemon.INSTANCE,
            FinalizerDaemon.INSTANCE,
            FinalizerWatchdogDaemon.INSTANCE,
    };
    @UnsupportedAppUsage
    public static void start() {
        for (Daemon daemon : DAEMONS) {
            daemon.start();
        }
    }

启动了我们熟知的四个守护线程。

总结:

梳理一下,在init创建zygote的过程中,zygote创建了Android世界的第一个虚拟机,而这个虚拟机是根据properties来进行配置的。在虚拟机创建的过程中,进行了堆的创建,以及守护进程等创建。