美文网首页
ART 启动简单理解

ART 启动简单理解

作者: 梧叶已秋声 | 来源:发表于2022-09-13 10:54 被阅读0次

写在开头:本篇为《深入理解Android:Java虚拟机ART》ART 启动相关的读书笔记。
由于书是以Android7代码去分析的,因此下文的代码链接也都是Android7的代码。
ART虚拟机是一个非常庞大和复杂的系统。学习这祥的一个系统, 我们必须要多方面、 多角度来研究它。这里先研究ART虚拟机的启动流程。

在Android系统中 , Java虚拟机是借由大名鼎鼎的Zygote进程来创建的 。Zygote是Java 世界的创造者一即Android中所有Java进程都由Zygote进程fork而来, 而Zygote进程自己又是Linux系统上的init进程通过解析配置脚本来启动的。假设目标设备为32位CPU架构, zygote进程对应的配置脚本文件是system/core/rootdir/init.zygote32.rc, 该文件描述了init该如何启动zygote进程。
文件位置:
http://aospxref.com/android-7.1.2_r39/xref/system/core/rootdir/init.zygote32.rc

service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
    class main
    socket zygote stream 660 root system
    onrestart write /sys/android_power/request_state wake
    onrestart write /sys/power/state on
    onrestart restart audioserver
    onrestart restart cameraserver
    onrestart restart media
    onrestart restart netd
    writepid /dev/cpuset/foreground/tasks

这里只关注第一行的内容。

  • service zygote:它告诉init进程, 现在我们要配置一个名为zygote的服务 服务是init的内部概念, 可以不用管它。
  • /system/bin/app_process :指明 zygote服务对应的二进制文件路径 init 创建服务的处理逻辑很简单. 就是fork 一个子进程来运行指定的程序。 对zygote 服务而言, 这个程序就是system/bin/app_process。
  • -Xzygote /system/bin --zygote --start-system-server :这一串内容是传递给app_process的启动参数

由上文的描述可知 zygote进程对应的程序实际上是system/bin/app_process。

http://aospxref.com/android-7.1.2_r39/xref/frameworks/base/cmds/app_process/app_main.cpp

int main(int argc, char* const argv[])
{
...
//AppRuntime是一个类,定义在app_main.cpp涓中。其基类是AndroidRuntime
    AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
   ...
   while (i < argc) {
        const char* arg = argv[i++];
//zygote脚本里的启动参数为
//"-Xzygote /systern/bin --Zygote --start-system-server"
        if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
//niceNarne将被设置为app_process的进程名 , 32位机对应的进程名 为“zygote",而64位机上该进程名为"zygote64"
            niceName = ZYGOTE_NICE_NAME;
        } 
     ...
    }
   ...


    if (zygote) {
 //调用基类AndroidRuntime的start函数       runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
    } else if (className) {
        runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
        return 10;
    }
}

接着来看AndroidRuntime的start函数。
http://aospxref.com/android-7.1.2_r39/xref/frameworks/base/core/jni/AndroidRuntime.cpp

void AndroidRuntime::start(const char* className, const Vector<String8>& options, bool zygote)
{
...
//重点关注JniInvocation.Init函数和startVm函数,它们和启动ART虚拟机有关
    /* start the virtual machine */
    JniInvocation jni_invocation;
    jni_invocation.Init(NULL);
    JNIEnv* env;
    if (startVm(&mJavaVM, &env, zygote) != 0) {
        return;
    }
...
}

上述代码中和启动 ART 虚拟机密切相关的两个重要函数如下所示。

  • JniInvocation的Init函数:它将加载ART虚拟机的核心动态库
  • AndroidRuntime的startVm函数:在ART虚拟机对应的核心动态库加载到Zygote进程后,该函数将启动ART虚拟机。

1.1 JniInvocation lnit 函数介绍

http://aospxref.com/android-7.1.2_r39/xref/libnativehelper/JniInvocation.cpp

bool JniInvocation::Init(const char* library) {
#ifdef __ANDROID__
  char buffer[PROP_VALUE_MAX];
#else
  char* buffer = NULL;
#endif
  //art核心库是通过动态加载so的方式加载到zygote进程的,GetLibrary根据情况返回
  //目标so的文件名,正常情况下加载的art核心动态库文件名为libart.so
  library = GetLibrary(library, buffer);
  const int kDlopenFlags = RTLD_NOW | RTLD_NODELETE;
  handle_ = dlopen(library, kDlopenFlags);
...
//从libart.so中找到 JNI_GetDefaultJavaVMInitArgs 函数的地址(也就是函数指针),将该地址存储到JNI_GetDefaultJavaVMInitArgs_中
  if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetDefaultJavaVMInitArgs_),
                  "JNI_GetDefaultJavaVMInitArgs")) {
    return false;
  }
  //从libart.so中找到 JNI_CreateJavaVM 函数,它就是创建虚拟机的入口函数。该函数的地址保存在JNI_CreateJavaVM_变量中
  if (!FindSymbol(reinterpret_cast<void**>(&JNI_CreateJavaVM_),
                  "JNI_CreateJavaVM")) {
    return false;
  }
  //从libart.so中找到 JNI_GetCreatedJavaVMs 函数
  if (!FindSymbol(reinterpret_cast<void**>(&JNI_GetCreatedJavaVMs_),
                  "JNI_GetCreatedJavaVMs")) {
    return false;
  }
  return true;
}

从libart.so里取出并保存三个函数的函数指针:

  • 这三个函数的代码位于java_vm_ext.cc中。
  • JNI_CreateJavaVM 用于创建Java虚拟机,所以它是最关键的。

1.2 AndroidRuntime startVm函数介绍

接着来看 AndroidRuntime::startVm。
http://aospxref.com/android-7.1.2_r39/xref/frameworks/base/core/jni/AndroidRuntime.cpp

int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote)
{
    JavaVMInitArgs initArgs;
.... //这段省略的代码非常长. 其主要功能是为ART虚拟机准备启动参数
    /*
     * Initialize the VM.
     *
     * The JavaVM* is essentially per-process, and the JNIEnv* is per-thread.
     * If this call succeeds, the VM is ready, and we can start issuing
     * JNI calls.
     */
//调用JNI_CreateJavaVM。注意,该函数和JniInvocation Init 从 libart.so取出的 JNI_CreateJavaVM 函数同名,但他们是不同的函数。
//JniInvocation Init 取出的那个函数的地址保存在 JNI_CreateJavaVM_ (其名称后多一个下划线)变量中,这一点容易混淆
    if (JNI_CreateJavaVM(pJavaVM, pEnv, &initArgs) < 0) {
        ALOGE("JNI_CreateJavaVM failed\n");
        return -1;
    }

    return 0;

这里书中有一点错误,JNI_CreateJavaVM 不是定义在 AndroidRuntime.cpp 中,而是 JniInvocation.cpp 中。

如上述代码中的注释所言,JNI_CreateJavaVM 函数并非是JniInovcation Init从libart.so获取的那个JNI_CreateJavaVM函数。 相反,它是直接在AndroidRuntime.cpp中定义的。

http://aospxref.com/android-7.1.2_r39/xref/libnativehelper/JniInvocation.cpp

extern "C" jint JNI_CreateJavaVM(JavaVM** p_vm, JNIEnv** p_env, void* vm_args) {
//调用JniInvocation 中的 JNI_CreateJavaVM,而JniInvocation又会调用 libart.so 中的JNI_CreateJavaVM函数。
  return JniInvocation::GetJniInvocation().JNI_CreateJavaVM(p_vm, p_env, vm_args);
}

这里和 libart.so 关联上了。下面来看 libart.so 中的这个 JNI_CreateJavaVM 函数。
文件位置:
http://aospxref.com/android-7.1.2_r39/xref/art/runtime/java_vm_ext.cc#939

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);
 ...//为虚拟机准备参数
//创建Runtime对象,它是ART虚拟机的化神
  if (!Runtime::Create(options, ignore_unrecognized)) {
    return JNI_ERR;
  }

  //加载其他关键动态库,它们的文件路径由/etc/public.libraries.txt文件描述
  android::InitializeNativeLoader();
//获取刚创建的Runtime对象
  Runtime* runtime = Runtime::Current();
/启动Runtime对象
  bool started = runtime->Start();
...
//获取JNI Env 和 Java VM 对象
  *p_env = Thread::Current()->GetJniEnv();
  *p_vm = runtime->GetJavaVM();
  return JNI_OK;
}

在上述libart.so的JNI_CreateJavaVM代码中,我们见到了ART 虚拟机的化身Runtime(即ART虚拟机在代码中是由Runtime类来表示的)。其中:

  • Runtime Create 将创建一个Runtime 对象。
  • Runtime Start 函数将启动这个Runtime对象,也就是启动Java虚拟机。

来看看Runtime 对象的创建。

VM和Runtime
虚拟机一词英文为Virtual Machine,Runtime则是另一个在虚拟机技术领域常用于表示虚拟机的单词。Runtime也被翻译为运行时。在ART虚拟机Native层代码中,Runtime是一个类。而JDK源码里也有一个Runtime类(位于java.lang包下)。这个Java Runtime 类提供了一个针对整个虚拟机层面而言的API,比如exit(退出虚拟机)、gc(触发垃圾回收)、load(加载动态库)等。

2.Runtime Create介绍

2.1 Create函数介绍

http://aospxref.com/android-7.1.2_r39/xref/art/runtime/runtime.cc

bool Runtime::Create(const RuntimeOptions& raw_options, bool ignore_unrecognized) {
  RuntimeArgumentMap runtime_options;
  return ParseOptions(raw_options, ignore_unrecognized, &runtime_options) &&
      Create(std::move(runtime_options));
}

虚拟机是一个复杂系统,所以它有很多控制参数。创建Runtime时,调用者将这些参数信息放在本函数的入参 raw_options 对象中,该对象的类型是RuntimeOptions。
不过,Runtime内部却使用类型为RuntimeArgumentMap的对象来存储参数。 下面这段代码中,ParseOptions 函数将存储在 raw_options 里的参数信息提取井保存到 runtime_options 对象里, 而 runtime_options 的类型就是 RuntimeArgumentMap 。

上述代码中

  • ParseOptions 先将外部调用者传入的参数信息(保存在 raw_options 中)提取并保存到 runtime_options 里
  • 然后再用 runtime_options 作为入参来创建 (Create) 一个 Runtime 对象

ART 虚拟机所需的参数信息(包括参数名、 参数类型、默认值)都定义在 runtime_options.def 文件中。

http://aospxref.com/android-7.1.2_r39/xref/art/runtime/runtime_options.def

RUNTIME_OPTIONS_KEY (Unit,                Zygote)
RUNTIME_OPTIONS_KEY (Unit,                Help)
RUNTIME_OPTIONS_KEY (Unit,                ShowVersion)
RUNTIME_OPTIONS_KEY (std::string,         BootClassPath)
RUNTIME_OPTIONS_KEY (ParseStringList<':'>,BootClassPathLocations)  // std::vector<std::string>
RUNTIME_OPTIONS_KEY (std::string,         ClassPath)
RUNTIME_OPTIONS_KEY (std::string,         Image)
RUNTIME_OPTIONS_KEY (Unit,                CheckJni)

RUNTIME_OPTIONS_KEY 定义了一个虚拟机控制参数。

了解 RuntimeOptions 后,接着来看 Create 函数 。
http://aospxref.com/android-7.1.2_r39/xref/art/runtime/runtime.cc

bool Runtime::Create(RuntimeArgumentMap&& runtime_options) {
  // TODO: acquire a static mutex on Runtime to avoid racing.
  //一个虚拟机进程中只有一个Runtime对象,名为instance_,采用单例方式来创建
  if (Runtime::instance_ != nullptr) {
    return false;
  }
  //创建Runtime对象
  instance_ = new Runtime;
  //用保存了虚拟机控制参数信息的 runtime_options 来初始化 这个 runtime 对象
  //重点来看Init函数
  if (!instance_->Init(std::move(runtime_options))) {
    // TODO: Currently deleting the instance will abort the runtime on destruction. Now This will
    // leak memory, instead. Fix the destructor. b/19100793.
    // delete instance_;
    instance_ = nullptr;
    return false;
  }
  return true;
}

2.2 Init函数介绍

Init 是 runtime 创建过程中最核心的函数。ART虚拟机中大部分重要模块和关键数据结构都将亮相。
http://aospxref.com/android-7.1.2_r39/xref/art/runtime/runtime.cc

bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
   ...
  RuntimeArgumentMap runtime_options(std::move(runtime_options_in));
  //关键模块之 MemMap : 用于管理内存映射。 ART 大量使用了内存映射技术。比如 .oat 文件就会通过 mmap 映射到虚拟机进程的虚拟内存中来。 
  MemMap::Init();
  //关键模块之 OatFileManager : art 虚拟机 会打开多个 oat 文件,通过该模块可统一管理它们
  oat_file_manager_ = new OatFileManager;
  //关键模块之 Monitor :和Java 中的 Monitor 有关,用于实现线程同步的模块。
  Monitor::Init(runtime_options.GetOrDefault(Opt::LockProfThreshold));
 ...
 // 关键模块之 Heap : heap 是 art 虚拟机中非常重要的模块
  heap_ = new gc::Heap(...);
  ...
  //关键模块之 JavaVmExt :JavaVmExt 就是 JNI 中代码 Java 虚拟机 的对象,其基类为JavaVM,真实类型为 JavaVmExt。根据 JNI 规范,一个进程只有唯一的一个 JavaVm 对象。对 ART 虚拟机来说,这个 JavaVm 对象就是此处的 java_vm_
  java_vm_ = new JavaVMExt(this, runtime_options);
  //关键模块之 Thread : Thread 是虚拟机中代表线程的类,下面两个函数调用 Thread 类的 Startup 和 Attach 以初始化虚拟机主线程
  Thread::Startup();
   Thread* self = Thread::Attach("main", false, nullptr, false);
   ...
   //关键模块之 ClassLinker :ClassLinker 也是非常重要的模块。从其命名可以看出,它处理和 class 有关的工作,比如解析某个类、寻找某个类等。 
   class_linker_ = new ClassLinker(intern_table_);
   ...
}

目标是了解虚拟机的启动流程,其他的细节暂时忽略,大致过一遍。

2.2.1 MemMap 和 OatFileManager 模块

MemMap
MemMap 是一个辅助工具类, 它封装了和内存映射(memory map) 有关的操作。
http://aospxref.com/android-7.1.2_r39/xref/art/runtime/mem_map.h#53

class MemMap {
//每一个MemMap对象都有一个名字
  const std::string& GetName() const {
    return name_;
  }
//针对这块映射内存的保护措施, 比如是否可读、可写、可执行等
  int GetProtect() const {
    return prot_;
  }

/*ART对内存使用非常计较. 很多地方都使用了内存监控技术比如使用STL标准容器类, ART将
监控容器里内存分配的情况。当然, 监控内存分配是有代价的, 所以ART设计了一个编译常量
(constexpr)来控制是否启用内存监控。下而这行代码中. Maps是 AllocationTrackingMultiMap 类型的别名, AllocationTrackingMultiMap真实类型是
multimap , AllocationTracking 即是TrackAllocation (跟踪分配)之意*/
  typedef AllocationTrackingMultiMap<void*, MemMap*, kAllocatorTagMaps> Maps;
}

/*ART对线程安全的问题也是倍加小心比如,下面这行代码在声明-个名为 maps_ 的静态成员变量之
后, 还使用了一个 GUARDED_BY 宏,宏里有一个参数。从其命名可以看出, mem_maps_lock_ 该是
一个互斥锁所以,第一次看到这行代码的读者可能会猜测, 这是想表达使用maps_ 时需要先拿到
mem_maps_lock_ 锁的意思吧?没错*/

 static Maps* maps_ GUARDED_BY(Locks::mem_maps_lock_);

/* 
MapAnonymous :用于映射一块匿名内存, use_ashmen 默认为 true ,
表示将从 android 系统里特有的 ashmem 设备(一种用于进程间共享内存的虚拟设备。
ashmem是 anonymous shared memory 的简写,表示匿名共享内存,是 android 系统上常用的进程间共享内存的方法)中分配并映射内存。
*/
  static MemMap* MapAnonymous(const char* name,
                              uint8_t* addr,
                              size_t byte_count,
                              int prot,
                              bool low_4gb,
                              bool reuse,
                              std::string* error_msg,
                              bool use_ashmem = true);
        
// MapFile:将其个文件映射到内存                     
 static MemMap* MapFile(size_t byte_count,
                         int prot,
                         int flags,
                         int fd,
                         off_t start,
                         bool low_4gb,
                         const char* filename,
                         std::string* error_msg) {
    return MapFileAtAddress(nullptr,
                            byte_count,
                            prot,
                            flags,
                            fd,
                            start,
                            /*low_4gb*/low_4gb,
                            /*reuse*/false,
                            filename,
                            error_msg);
  }

OatFileManager
OatFileManager 用于管理虚拟机加载的oat文件dex字节码编译成机器码后,相关内容会存储在一个以oat为后缀名的文件里。我们先来简单认识OAT文件的格式。
OAT文件格式简介:
OAT文件包含一个OatHeader头结构。注意.这个OatHeader信息并不存储在OAT文件的头部。OAT文件其实是一个ELF格式的文件,相关信息存储在ELF对应的段中。
Oat文件是怎么来的呢?它是对jar包或apk包中的dex项(名为classes.dex、classes2.dex、classes3.dex等.其实就是dex文件打包到jar或apk里了。以后我们统称它们为dex文件.而不必理会它们是单独的.dex文件还是jar或apk包中的一项)进行编译处理后得到的。jar或apk中可包含多个dex项(即所谓的multidex),每一个jar或apk中的所有dex文件在oat文件中对应都有一个OatDexFile项。 OatDexFile项存储了一些信息,比如它所对应的dex文件的路径、dex文件的校验以及其他各种信息在oat文件中的位置(offset)等。

https://www.jianshu.com/p/bdb6c29aca83
OAT文件里的一个DexFile项包含一个.dex文件的全部内容。通过在OAT文件中包含dex文件的内容,ART虚拟机只需要加载OAT文件即可获取相关信息,而不需要单独再打开dex文件了。当然,这种做法也使得OAT文件尺寸较大。

OatFileManager类介绍
http://aospxref.com/android-7.1.2_r39/xref/art/runtime/oat_file_manager.h#46

class OatFileManager {
 public:
  OatFileManager() : have_non_pic_oat_file_(false) {}
  ~OatFileManager();

// 往OatManager中添加一个OatFile对象
  const OatFile* RegisterOatFile(std::unique_ptr<const OatFile> oat_file)

/* ART虚拟机会加载多个OAT文件。其中:
(1) zygote作为第一个Java进程会首先加载一些基础与核心的oat文件。这些oat文件里包含了Android系统中所有Java程序所依赖的基础功能类(比如Java标准类)。这些oat文件称之为boot oat文件(与之对应的一个名词叫boot image。下文将详细介绍boot image的相关内
容)
(2) APP进程通过zygote fork得到,然后该APP进程将加栽APK包经过dex2oat得到的oat文件。
该APP对应的oat文件叫app image。下面的 GetBootOatFiles 将返回 boot oat 文件信息.
返回的是一个vector数组*/
std::vector<const OatFile*> GetBootOatFiles() const;
}

/* 将包含在boot镜像里的oat文件信息注册到OatFileManager中。ImageSpace代表一个由映射内
存构成的区域(Space), zygote启动后,会将boot oat文件通过memap映射到内存,从而得到
一个ImageSpace。下面将详细介绍和 ImageSpace 相关的内容*/
std::vector<const OatFile*> RegisterImageOatFiles(std::vector<gc::space::ImageSpace*> spaces)

// 从Oat文件中找到指定的dex文件。dex文件由DexFile对象表示
  std::vector<std::unique_ptr<const DexFile>> OpenDexFilesFromOat

往OatFileManager中注册Oatfile对象非常简单,就是将OatFile对象保存到oat files_ (对象为std set)容器中
http://aospxref.com/android-7.1.2_r39/xref/art/runtime/oat_file_manager.cc?fi=RegisterOatFile#RegisterOatFile

const OatFile* OatFileManager::RegisterOatFile(std::unique_ptr<const OatFile> oat_file) {
  WriterMutexLock mu(Thread::Current(), *Locks::oat_file_manager_lock_);
  DCHECK(oat_file != nullptr);
  if (kIsDebugBuild) {
    CHECK(oat_files_.find(oat_file) == oat_files_.end());
    for (const std::unique_ptr<const OatFile>& existing : oat_files_) {
      CHECK_NE(oat_file.get(), existing.get()) << oat_file->GetLocation();
      // Check that we don't have an oat file with the same address. Copies of the same oat file
      // should be loaded at different addresses.
      CHECK_NE(oat_file->Begin(), existing->Begin()) << "Oat file already mapped at that location";
    }
  }
  have_non_pic_oat_file_ = have_non_pic_oat_file_ || !oat_file->IsPic();
  const OatFile* ret = oat_file.get();
  oat_files_.insert(std::move(oat_file));
  return ret;
}

关于boot oat 文件里所包含的系统基础类。frameworks/base 下有一个preloaded-classes 文件. 其内容是希望加载到zygote 进程里的类名(按照JNI 格式定义), 这些类包含在不同的boot oat 文件里。
http://aospxref.com/android-7.1.2_r39/xref/frameworks/base/preloaded-classes

[B
[C
[D
[F
[I
[J
[Landroid.accounts.Account;
[Landroid.animation.Animator;
[Landroid.animation.Keyframe$FloatKeyframe;
[Landroid.animation.Keyframe$IntKeyframe;
[Landroid.animation.Keyframe$ObjectKeyframe;
[Landroid.animation.Keyframe;
[Landroid.animation.PropertyValuesHolder;
[Landroid.app.LoaderManagerImpl;
[Landroid.content.ContentProviderResult;
[Landroid.content.ContentValues;
[Landroid.content.Intent;
...
[Ljava.lang.Short;
[Ljava.lang.StackTraceElement;
[Ljava.lang.String;
[Ljava.lang.Thread$State;
[Ljava.lang.Thread;
[Ljava.lang.ThreadGroup;
[Ljava.lang.ThreadLocal$ThreadLocalMap$Entry;
[Ljava.lang.Throwable;
...

由于zygote 是Java 世界的第一个进程, 其他
APP 进程(包括system server 进程)均由zygote 进程fork 而来所以:

  • 这些加载到zygote 进程里的类也叫预加载类, 即所谓的preloaded classes。
  • 根据linux 进程fork 的机制,其他APP 进程从zygote fork 后, 将继承得到这些预加载的类。

fork采用的是copy-on-write,调用一次,返回两次。当父子进程任一方修改内存数据时(这是on-write时机),才发生缺页中断,从而分配新的物理内存(这是copy操作)。
fork()之后,kernel把父进程中所有的内存页的权限都设为read-only,然后子进程的地址空间指向父进程。当父子进程都只读内存时,相安无事。当其中某个进程写内存时,CPU硬件检测到内存页是read-only的,于是触发页异常中断,kernel就会把触发的异常的页复制一份,于是父子进程各自持有独立的一份。

2.2.2 Thread 模块

来看看和 art 虚拟机执行密切相关的 Thread 类。
http://aospxref.com/android-7.1.2_r39/xref/art/runtime/runtime.cc

 java_vm_ = new JavaVMExt(this, runtime_options);

  Thread::Startup();

  Thread* self = Thread::Attach("main", false, nullptr, false);

Thread 中的 Startup 和 Attach函数,重点是 Attach 函数。

Startup 函数介绍
http://aospxref.com/android-7.1.2_r39/xref/art/runtime/thread.cc#1557

void Thread::Startup() {
  CHECK(!is_started_);
  is_started_ = true;
  {
    // MutexLock to keep annotalysis happy.
    //
    // Note we use null for the thread because Thread::Current can
    // return garbage since (is_started_ == true) and
    // Thread::pthread_key_self_ is not yet initialized.
    // This was seen on glibc.
    MutexLock mu(nullptr, *Locks::thread_suspend_count_lock_);
    resume_cond_ = new ConditionVariable("Thread resumption condition variable",
                                         *Locks::thread_suspend_count_lock_);
  }
// pthread_key_create将被调用
//该函数将创建一块调用线程特有的数据区域. 即所谓的Thread Local Storage (简写为TLS)
  // Allocate a TLS slot.
CHECK_PTHREAD_CALL(pthread_key_create, (&Thread::pthread_key_self_, Thread::ThreadExitCallback),
                     "self key");

  // Double-check the TLS slot allocation.
  if (pthread_getspecific(pthread_key_self_) != nullptr) {
    LOG(FATAL) << "Newly-created pthread TLS slot is not nullptr";
  }
}

Attach函数介绍
http://aospxref.com/android-7.1.2_r39/xref/art/runtime/thread.cc

Thread* Thread::Attach(const char* thread_name, bool as_daemon, jobject thread_group,
                       bool create_peer) {
  Runtime* runtime = Runtime::Current();
...
  Thread* self;
  {
    MutexLock mu(nullptr, *Locks::runtime_shutdown_lock_);
...
      Runtime::Current()->StartThreadBirth();
      // 关键函数之一 构造函数
      self = new Thread(as_daemon);
      // 关键函数之二
      bool init_success = self->Init(runtime->GetThreadList(), runtime->GetJavaVM());
      Runtime::Current()->EndThreadBirth();
...
  }
// 关键函数之三
  self->InitStringEntryPoints();

  CHECK_NE(self->GetState(), kRunnable);
  self->SetState(kNative);
...
  return self;
}

Attach内部包含三个关键函数,先看第一个,Thread的构造函数。

Thread的构造函数
主要是完成对某些成员变量的初始化。
tlsPtr_ 是Thread 类中非常关键的结构体。
http://aospxref.com/android-7.1.2_r39/xref/art/runtime/thread.h

  struct PACKED(sizeof(void*)) tls_ptr_sized_values {
      tls_ptr_sized_values() : card_table(nullptr), exception(nullptr), stack_end(nullptr),
      managed_stack(), suspend_trigger(nullptr), jni_env(nullptr), tmp_jni_env(nullptr),
      self(nullptr), opeer(nullptr), jpeer(nullptr), stack_begin(nullptr), stack_size(0),
      stack_trace_sample(nullptr), wait_next(nullptr), monitor_enter_object(nullptr),
      top_handle_scope(nullptr), class_loader_override(nullptr), long_jump_context(nullptr),
      instrumentation_stack(nullptr), debug_invoke_req(nullptr), single_step_control(nullptr),
      stacked_shadow_frame_record(nullptr), deoptimization_context_stack(nullptr),
      frame_id_to_shadow_frame(nullptr), name(nullptr), pthread_self(0),
      last_no_thread_suspension_cause(nullptr), thread_local_objects(0),
      thread_local_start(nullptr), thread_local_pos(nullptr), thread_local_end(nullptr),
      mterp_current_ibase(nullptr), mterp_default_ibase(nullptr), mterp_alt_ibase(nullptr),
      thread_local_alloc_stack_top(nullptr), thread_local_alloc_stack_end(nullptr),
      nested_signal_state(nullptr), flip_function(nullptr), method_verifier(nullptr),
      thread_local_mark_stack(nullptr) {
      std::fill(held_mutexes, held_mutexes + kLockLevelCount, nullptr);
    }
...
    uint8_t* stack_end;

//和本线程关联的Jni环境对象
    JNIEnvExt* jni_env;

...
//指向包含本对象的Thread对象
    Thread* self;

//下面两个成员变量也和线程栈有关。详情见下文对线程栈的介绍
    uint8_t* stack_begin;
    // Size of the stack.
    size_t stack_size;
...
//jni_entrypoints :结构体,和JNI调用有关。里边只有一个函数指针成员变量,名为 pDlsymLookup。当 JNI 函数未注册时,这个成员变量将被调用以找到目标 JNI 函数。
    JniEntryPoints jni_entrypoints;
//quick_entrypoints :结构体,其成员变量全是函数指针类型,其定义可参考 quick_entrypoints_list.h
//它包含了一些由ART虚拟机提供的某些功能,而我们编译得到的机器码可能会用到它们。生产机器码时,
//需要生成对应的调用指令以跳转到这些函数。
    QuickEntryPoints quick_entrypoints;

...
} tlsPtr_;

接着来看关键函数之二 Init函数。
http://aospxref.com/android-7.1.2_r39/xref/art/runtime/thread.cc

bool Thread::Init(ThreadList* thread_list, JavaVMExt* java_vm, JNIEnvExt* jni_env_ext) {
...
//设置tlsPtr_里的 jni_entrypoints 和 quick_entrypoints
  InitTlsEntryPoints();
...
//下而这段代码将当前这个Thread对队设置到本线程的本地存储空间中去
#ifdef __ANDROID__
  __get_tls()[TLS_SLOT_ART_THREAD_SELF] = this;
#else
  CHECK_PTHREAD_CALL(pthread_setspecific, (Thread::pthread_key_self_, this), "attach self");
#endif
  DCHECK_EQ(Thread::Current(), this);

  tls32_.thin_lock_thread_id = thread_list->AllocThreadId(this);
//每一个线程将关联一个 JNIEnvExt对象。 它存储在 tlsPtr_jni_env 变量中。对主线程而言
// JNIEnvExt 对象由 Runtime 创建并传给代表主线程的Thread 对象,也就是此处的 Thread 对象
  if (jni_env_ext != nullptr) {
    DCHECK_EQ(jni_env_ext->vm, java_vm);
    DCHECK_EQ(jni_env_ext->self, this);
    tlsPtr_.jni_env = jni_env_ext;
  } else {
    tlsPtr_.jni_env = JNIEnvExt::Create(this, java_vm);
    if (tlsPtr_.jni_env == nullptr) {
      return false;
    }
  }
// Runtime对象中有一个 thread_list_ 成员变量,其类型是 ThreadList,用于存储虚拟机所创建的 Thread对象
  thread_list->Register(this);
  return true;
}

thread.cc这个类中有lnitStackHwm、InitCpu、InitTlsEntryPoints以及
InitInterpreterTls等init函数。

lnitStackHwm
本函数用于设置线程的线程栈。

Android平台上, 我们可通过调用pthread_ create来创建一个线程。
这里省略流程,直接贴出线程栈创建过程:

  • mmap 得到一块内存,其返回值为该内存的低地址(stack_base)
  • 设置该内存从低地址开始的某段区域(由guard_size)为不可访问。
  • 得到该内存段的高地址, 将其作为线程栈的栈底位置传递给clone系统调用 。

再来看lnitStackHwm等。说实话这里我没有看懂。so,先略过。

接着来看关键函数之三 InitStringEntryPoints函数。
通过函数名我们可判断它也是初始化某些EntryPoints, 而且可能是和字符串相关某些函数。
http://aospxref.com/android-7.1.2_r39/xref/art/runtime/thread.cc

void Thread::InitStringEntryPoints() {
  ScopedObjectAccess soa(this);
  QuickEntryPoints* qpoints = &tlsPtr_.quick_entrypoints;
  qpoints->pNewEmptyString = reinterpret_cast<void(*)()>(
      soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newEmptyString));
  qpoints->pNewStringFromBytes_B = reinterpret_cast<void(*)()>(
      soa.DecodeMethod(WellKnownClasses::java_lang_StringFactory_newStringFromBytes_B));
...
}

WellKnownClasses::java_lang_StringFactory_newEmptyString,这是一个静态变量,类型为 jmethodID (熟悉JNI的读者可能还记得,在JNI层中, jmethodID 用于表示一个Java方法,与之类似的是jFieldID,表示一个Java类中的成员)。 jmethodID 的真实数据类型并无标准规定,不同虚拟机实现会使用不同的数据类型。待会我们会看到ART虚拟机里的 jmethodID 到底是什么此处的 jmethodID 所表示的Java方法是 java.lang.StringFactor.newEmptyString 函数。

来看看ScopedObjectAccess 的 DecodeMethod 。
http://aospxref.com/android-7.1.2_r39/xref/art/runtime/scoped_thread_state_change.h?r=&mo=5941&fi=161#161

  ArtMethod* DecodeMethod(jmethodID mid) const SHARED_REQUIRES(Locks::mutator_lock_) {
    Locks::mutator_lock_->AssertSharedHeld(Self());
    DCHECK(IsRunnable());  // Don't work 
    //数据类型转换,将输入的 jmethodID 转换成 ArtMethod*。也就是说,一个 jmethodID,实际上指向的是一个 ArtMethod 对象.
    with raw objects in non-runnable states.
    return reinterpret_cast<ArtMethod*>(mid);
  }

StringFactory部分成员函数以及对应的jmethodID变量定义
http://aospxref.com/android-7.1.2_r39/xref/art/runtime/well_known_classes.cc

jmethodID WellKnownClasses::java_lang_StringFactory_newEmptyString;
jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromBytes_B;
jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BI;
jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BII;
jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BIII;
jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BIIString;
jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BString;
jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BIICharset;
jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromBytes_BCharset;
jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromChars_C;
jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromChars_CII;
jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromChars_IIC;
jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromString;
jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromStringBuffer;
jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromCodePoints;
jmethodID WellKnownClasses::java_lang_StringFactory_newStringFromStringBuilder;

2.2.3 Heap 模块

以先了解大概流程以及某些关键类的作用为主。
.art文件格式介绍
一个包含class.dex 项 的jar 或 apk 文件经由 dex2oat 进行编译处理后实际上会生成两个结果文件,一个是.oat文件,另一个是.art文件。

  • .oat文件:class.dex 内容 将被完整拷贝到.oat文件里。
  • .art文件:它就是ART虚拟机代码里经常提到的Image文件。

根据art文件的来源(比如它是从哪个jar包或apk包编译得来)。Image分boot镜像(boot image)和 app镜像(app image)。

  • 来源于某个apk的art文件成为APP镜像
  • 来自Android系统里的/framework下的那些jar包的art文件统称为boot镜像。

为什么叫Image?
首先,art文件加载到虚拟机中,都是通过mmap的方式去完成,其次,art文件的内容布局有严格组织,可以直接转换成对应的对象。
另外,一般而言,针对核心库的变异都会生成boot .art镜像文件,而针对app的编译则通过dex2oat相关选项来控制是否生成art文件。

创建ImageSpace对象
art文件将被映射到art虚拟机进程的内存里,该工作是通过ImageSpace的init函数完成的,其返回结果是一个ImageSpace对象。
http://aospxref.com/android-7.1.2_r39/xref/art/runtime/gc/space/image_space.cc

ImageSpace* ImageSpace::Init(const char* image_filename,
                             const char* image_location,
                             bool validate_oat_file,
                             const OatFile* oat_file,
                             std::string* error_msg) {
...
//总之,需牢记2点:第一, art虚拟机加载的是 dalvik-cache下的art文件。
//第二,dalvik-cache下的art文件和其他来源的art文件可能并不完全相同。某些情况下,虚拟机直接从 framework 等源目录下直接copy过来,有些情况下 虚拟机会对源art文件进行一些处理以提升安全性。
  std::unique_ptr<File> file;
  {
...
//打开 dalvik-cache 下的 art 文件   file.reset(OS::OpenFileForReading(image_filename));
...
  }
  ImageHeader temp_image_header;
  ImageHeader* image_header = &temp_image_header;
  {
//从该art文件中读取 ImageHeader,它位于文件的头部
    bool success = file->ReadFully(image_header, sizeof(*image_header));
...
  }
//获取该art文件的大小
  const uint64_t image_file_size = static_cast<uint64_t>(file->GetLength());
...

//取出ImageHeader的 section_ 数组中最后一个类型(kSectionImageBitmap)所对应的 ImageSection 对象。 这个section里存储的是位图空间的位置和大小。
  const auto& bitmap_section = image_header->GetImageSection(ImageHeader::kSectionImageBitmap);
...
//现在准备将art文件map到内存
  std::vector<uint8_t*> addresses(1, image_header->GetImageBegin());
...

//art 文件映射到内存后的 MemMap 对象就是它。
  std::unique_ptr<MemMap> map;
  std::string temp_error_msg;
  for (uint8_t* address : addresses) {
...
    if (storage_mode == ImageHeader::kStorageModeUncompressed) {
    //将art文件映射到zygote进程的虚拟内存空间
      map.reset(MemMap::MapFileAtAddress(address,
                                         image_header->GetImageSize(),
                                         PROT_READ | PROT_WRITE,
                                         MAP_PRIVATE,
                                         file->Fd(),
                                         0,
                                         /*low_4gb*/true,
                                         /*reuse*/false,
                                         image_filename,
                                         /*out*/out_error_msg));
    }
    ...
// 创建一个ImageSpace对象.
  // We only want the mirror object, not the ArtFields and ArtMethods.
  std::unique_ptr<ImageSpace> space(new ImageSpace(image_filename,
                                                   image_location,
                                                   map.release(),
                                                   bitmap.release(),
                                                   image_end));
...

  // 返回所创建的space对象
  return space.release();
}
 

总结:

  • ART虚拟机的一个重要的特点就是大量使用映射内存。
  • 一个.art文件加载到虚拟机进程的内存空间后对应一个ImageSpace对象。

Heap构造函数第一部分
Heap构造函数相当复杂,代码长达400多行。if/else等分支情况非常多。更有甚者,其
调用流程中甚至可能会启动dex2oat或patchoat等具他进程来做一些更为复杂的工作。这导致
Heap构造函数不仅代码复杂.而且执行时间也可能很长。先学习部分。
http://aospxref.com/android-7.1.2_r39/xref/art/runtime/gc/heap.cc

Heap::Heap(size_t initial_size,
           size_t growth_limit,
           size_t min_free,
           size_t max_free,
... /* 非常多的参数 */):...  /* 初始化列表也很长 */{
/*
Heap之所以复杂的原因是它负责管理 ART虚拟机
中各种内存资源(不同的Space)、GC(Garbage Collect,垃圾回收)模块、.art文件加载、Java指令编译后得到的机器码和虚拟内存相关模块交互等重要功能
 */
 Runtime* const runtime = Runtime::Current();
  const bool is_zygote = runtime->IsZygote();
...
//垃圾回收相关
 ChangeCollector(desired_collector_type_);
//创建两个 HeapBitmap 对象
   live_bitmap_.reset(new accounting::HeapBitmap(this));
  mark_bitmap_.reset(new accounting::HeapBitmap(this));
  
  // 遍历数组各个元素,加载每一个art文件,不过,该数组最开始只有一个元素,所以下面的for循环中将添加其他的art文件。注意,这只是针对boot镜像而言。
   for (size_t index = 0; index < image_file_names.size(); ++index) {
/*
加载art文件,返回一个 ImageSpace 对象。CreateBootimage 的内容非常复杂。比
如,如果art文件不存在,则会fork一个子进程以执行dex2oat进行编译,假设本例所需的 art 文件已经就绪。那么,CreatBootimage 内部
将调用 ImageSpace 的 init 函数以创建 ImageSpace 对象。
 */
 space::ImageSpace* boot_image_space = space::ImageSpace::CreateBootImage(
          image_name.c_str(),
          image_instruction_set,
          index > 0,
          &error_msg);
...
    }
... 
}

Heap构造函数, 它主要完成了boot镜像所需art文件的加载,然后得到一
系列的ImageSpace对象,最后再保存到Heap对应的成员变量中。

2.2.4 JavaVMExt 和 JNIEnvExt

本节讨论JNI中最常见的两个类JavaVM和JNIEnv。

  • JavaVM在JNI层中表示Java虚拟机。它的作用有点像Runtime。只不过JNI作为一种规范, 它必须设定一个统一的结构, 即此处的JavaVM, 不同的虚拟机实现里, 真实的虚拟机对象可以完全不一样, 比如art虚拟机中的Runtime才是当之无愧的虚拟机。另外,一个Java进程只有一个JavaVM实例。在ART虚拟机中,JavaVM实际代表的是JavaVMExt类。
  • JNIEnv代表JNI环境,每一个需要和Java交互(不管是Java层进入Native层, 还是Native层进入Java层)的线程都有一个独立的JNIEnv对象。同理,JNIEnv是JNI规范里指定的数据结构,不同虚拟机有不同的实现。在ART虚拟机中,JNIEnv实际代表的是JNIEnvExt类。

JavaVMExt
JavaVMExt的创建
http://aospxref.com/android-7.1.2_r39/xref/art/runtime/runtime.cc

  java_vm_ = new JavaVMExt(this, runtime_options);

http://aospxref.com/android-7.1.2_r39/xref/art/runtime/java_vm_ext.h#39

class JavaVMExt : public JavaVM {
}

JavaVMExt 继承自 JavaVM ,是派生类。
JavaVM 是个_JavaVM结构体。

http://aospxref.com/android-7.1.2_r39/xref/libnativehelper/include/nativehelper/jni.h#141

struct _JavaVM;
...
typedef _JavaVM JavaVM;

来看看_JavaVM结构体的定义。
http://aospxref.com/android-7.1.2_r39/xref/libnativehelper/include/nativehelper/jni.h#1053

struct _JavaVM {
    const struct JNIInvokeInterface* functions;

#if defined(__cplusplus)
    jint DestroyJavaVM()
    { return functions->DestroyJavaVM(this); }
    jint AttachCurrentThread(JNIEnv** p_env, void* thr_args)
    { return functions->AttachCurrentThread(this, p_env, thr_args); }
    jint DetachCurrentThread()
    { return functions->DetachCurrentThread(this); }
    jint GetEnv(void** env, jint version)
    { return functions->GetEnv(this, env, version); }
    jint AttachCurrentThreadAsDaemon(JNIEnv** p_env, void* thr_args)
    { return functions->AttachCurrentThreadAsDaemon(this, p_env, thr_args); }
#endif /*__cplusplus*/
};

JNIInvokeInterface也是结构体。其中,JNIInvokeInterface的AttachCurrentThread、GetEnv等成员变量的数据类型都是函数指针。
而关于 宏 __cplusplus,具体可看这篇: 关于JNIEnv和JavaVM(C C++ 区别)
在C中:
使用JNIEnv* env要这样 (env)->方法名(env,参数列表)
使用JavaVM
vm要这样 (vm)->方法名(vm,参数列表)
在C++中:
使用JNIEnv
env要这样 env->方法名(参数列表)
使用JavaVM* vm要这样 vm->方法名(参数列表)
上面这二者的区别是,在C中必须先对env和vm间接寻址(得到的内容仍然是一个指针),在调用方法时要将env或vm传入作为第一个参数。C++则直接利用env和vm指针调用其成员。

JNIEnvExt
JNIEnvExt的思路和JavaVMExt类似。
http://aospxref.com/android-7.1.2_r39/xref/libnativehelper/include/nativehelper/jni.h#140

 struct _JNIEnv;
...
 typedef _JNIEnv JNIEnv;
...
struct _JNIEnv {
    /* do not rename this; it does not seem to be entirely opaque */
    const struct JNINativeInterface* functions;

#if defined(__cplusplus)

    jint GetVersion()
    { return functions->GetVersion(this); }

    jclass DefineClass(const char *name, jobject loader, const jbyte* buf,
        jsize bufLen)
    { return functions->DefineClass(this, name, loader, buf, bufLen); }

    jclass FindClass(const char* name)
    { return functions->FindClass(this, name); }

...
#endif /*__cplusplus*/
};

http://aospxref.com/android-7.1.2_r39/xref/libnativehelper/include/nativehelper/jni.h

struct JNINativeInterface {
    void*       reserved0;
    void*       reserved1;
    void*       reserved2;
    void*       reserved3;

    jint        (*GetVersion)(JNIEnv *);
    jclass      (*DefineClass)(JNIEnv*, const char*, jobject, const jbyte*,
                        jsize);
    jclass      (*FindClass)(JNIEnv*, const char*);

    jmethodID   (*FromReflectedMethod)(JNIEnv*, jobject);
    jfieldID    (*FromReflectedField)(JNIEnv*, jobject);
    /* spec doesn't show jboolean parameter */
    jobject     (*ToReflectedMethod)(JNIEnv*, jclass, jmethodID, jboolean);
...
}

现在来看JNIEnvExt ,是JNIEnv 的派生类。其创建是通过Create。
http://aospxref.com/android-7.1.2_r39/xref/art/runtime/jni_env_ext.h#36

struct JNIEnvExt : public JNIEnv {
  static JNIEnvExt* Create(Thread* self, JavaVMExt* vm);
}

http://aospxref.com/android-7.1.2_r39/xref/art/runtime/jni_env_ext.cc

JNIEnvExt* JNIEnvExt::Create(Thread* self_in, JavaVMExt* vm_in) {
  std::unique_ptr<JNIEnvExt> ret(new JNIEnvExt(self_in, vm_in));
  if (CheckLocalsValid(ret.get())) {
    return ret.release();
  }
  return nullptr;
}

其构造函数如下
http://aospxref.com/android-7.1.2_r39/xref/art/runtime/jni_env_ext.cc#JNIEnvExt

JNIEnvExt::JNIEnvExt(Thread* self_in, JavaVMExt* vm_in)
    : self(self_in),
      vm(vm_in),
      local_ref_cookie(IRT_FIRST_SEGMENT),
      locals(kLocalsInitial, kLocalsMax, kLocal, false),
      check_jni(false),
      runtime_deleted(false),
      critical(0),
      monitors("monitors", kMonitorsInitial, kMonitorsMax) {
//GetJniNativeInterface 返回全局静态对象gJniNativeInterface
  functions = unchecked_functions = GetJniNativeInterface();
  if (vm->IsCheckJniEnabled()) {
    SetCheckJniEnabled(true);
  }
}

http://aospxref.com/android-7.1.2_r39/xref/art/runtime/jni_internal.cc?fi=GetJniNativeInterface#GetJniNativeInterface

const JNINativeInterface* GetJniNativeInterface() {
  return &gJniNativeInterface;
}

http://aospxref.com/android-7.1.2_r39/xref/art/runtime/jni_internal.cc?fi=GetJniNativeInterface#gJniNativeInterface

const JNINativeInterface gJniNativeInterface = {
  nullptr,  // reserved0.
  nullptr,  // reserved1.
  nullptr,  // reserved2.
  nullptr,  // reserved3.
  JNI::GetVersion,
  JNI::DefineClass,
  JNI::FindClass,
...
}

这些函数为JNI类的静态成员变量,Java和JNI的函数
通过JNINativeInterface 关联起来。


https://www.cnblogs.com/mazhimazhi/p/15528565.html

JavaVM和JNIEnv这2个类的具体使用可参考这篇:
https://www.jianshu.com/p/d46ebdcfc3d9
之前简单整理了一下。

2.2.5 ClassLinker

在Java中,Class是最为重要的信息组织单元。所以,本节的主角 ClassLinker 也是ART中当仁不让的核心类。正如其类名所示 ——ClassLinker——类的连接器,即将类关联和管理起来。
Runtime Init 函数中和 ClassLinker 的关键代码,如下所示。

bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
...
// class_linker_ 是 runtime 的成员变量,其类型是 ClassLinker
  class_linker_ = new ClassLinker(intern_table_);
// 根据boot镜像的内容初始化这个 ClassLinker 对象 
 bool result = class_linker_->InitFromBootImage(&error_msg);
...
}

ClassLinker 初始化流程暂时略过。
这里只关注一个知识点:
类是如何被加载的?
这里涉及到ClassLoader 相关知识点。
可参考这几篇文档:
Android类加载器ClassLoader
通俗易懂的双亲委派机制
类是如何被加载的?

类的执行过程

https://blog.csdn.net/u014775977/article/details/120378875

类的加载过程

https://blog.csdn.net/u014775977/article/details/120378875
1)加载、验证、准备、初始化这四个阶段的发生顺序与图中所描述的顺序相同,唯独解析阶段,它是不太固定的,它有可能发生在初始化之前,但是也有可能发生在初始化之后;
2)这几个阶段也并不是完全执行完某一个阶段,才可以发生下一个阶段,大部分情况下都是交叉混合进行的。

类加载器
JVM预定义了三种类加载器,分别是引导类加载器、拓展类加载器、应用类加载器

https://blog.csdn.net/u014775977/article/details/120378875

双亲委派机制工作原理:
1.如果一个类加载器收到了类加载请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行。
2.如果父类的加载器还存在其父类加载器,则进一步向上委托,依次递归,请求最终会到达顶层的启动类加载器。(从这里就可以看出来,类加载请求都会先到达启动类加载器)
3.如果父类加载器可以完成类加载任务,就成功返回,倘若无法完成此加载任务,则委派给它的子加载器去加载。如果有个类加载请求来了,会一直向上委托,直到引导类加载器;然后引导类加载器尝试加载,如果它不能加载,则会给他的子加载器扩展类加载器加载;如果扩展类加载器还是不能加载;则再到下一级系统类加载器。

双亲委派机制的优势
1.避免类的重复加载。一旦一个类被父类加载器加载之后,就不会再被委派给子类进行加载。
2.保护程序安全。

总结可看这张图


https://blog.csdn.net/codeyanbao/article/details/82875064 https://blog.csdn.net/codeyanbao/article/details/82875064

3. 总结

围绕 Runtime 对象的创建过程,介绍了 ART 虚拟机代码中一些关键模块、关键类和它们的功能。

  • Runtime 对象是虚拟机的化身。整个虚拟机包含很多模块,这些模块对应的对象都可以通过 Runtime 相关接口获取。
  • Thread 类代表虚拟机内部的执行线程,它和线程堆栈的设置、代码的执行等息息相关。
  • Heap 类封装了加载到虚拟机进程里的各种内存映射对象,包括加载镜像文件的 ImageSpace ,用于分配内存的 MallocSpace 。Heap 还包含GC 相关很多功能。
  • ClassLinker 用于管理虚拟机所加载的各种 Class 信息
  • JavaVMExt 是 JavaVm 的派生类,是 ART 虚拟机 JNI 层中 Java 虚拟机的化身。还有一些其他辅助类,比如 MemMap、OatFileManager、GcRoot等。
  • 最后,有一个很重要的知识点是 oat 和 art 的文件格式。虚拟机中的很多信息都是从 art 或 oat 文件里读取的。

参考链接:
类是如何被加载的?
Android类加载器ClassLoader
关于JNIEnv和JavaVM(C C++ 区别)

相关文章

  • ART 启动简单理解

    写在开头:本篇为《深入理解Android:Java虚拟机ART》ART 启动相关的读书笔记。由于书是以Androi...

  • 15 启动更多ART和价值流,扩展到投资组合

    步骤10:启动更多的ART和价值流 启动更多ART 准备ART启动 培训团队并启动ART 教练ART执行 启动更多...

  • 准备启动ART

    短期胜利有助于建立必要的动力。——Kotter 准备ART启动 这是SAFe®实施路线图系列的第七篇。点击这里查看...

  • ART和Dalvik区别 (ART: Ahead of Time

    ART和Dalvik区别 Art上应用启动快,运行快,但是耗费更多存储空间,安装时间长,总的来说ART的功效就是"...

  • ART和Dalvik区别

    Art上应用启动快,运行快,但是耗费更多存储空间,安装时间长,总的来说ART的功效就是"空间换时间"。 ART: ...

  • Android 系统的Zygote初始化过程

    ART 在上文的Android 系统的启动过程中说到Android的虚拟机ART(AndroidRuntime) ...

  • SurfaceFlinger简单理解

    本文会从SurfaceFlinger启动和画面显示流程2个方面简单分析理解。 init进程启动SurfaceFli...

  • ART Heap学习笔记

    boot.art@classes.dex和boot.art@classes.oat在系统第一次启动时由系统类生成。...

  • Android 中级(待续)

    SurfaceView 蓝牙 Android Binder 机制-JVM-JVM源码分析之JVM启动流程 Art ...

  • 14 实施敏捷发布火车

    步骤7:准备ART启动 定义ART 谁是业务负责人? 谁对业务成果负责 谁能现在和不久的将来评估解决方案的技术效能...

网友评论

      本文标题:ART 启动简单理解

      本文链接:https://www.haomeiwen.com/subject/cebcortx.html