Dalvik虚拟机和ART虚拟机
目录
一,背景知识
1.1 Dalvik虚拟机概述
1.2 Dalvik虚拟机的启动过程
Dalvik虚拟机的运行过程
一,背景知识
Android应用程序是运行在Dalvik虚拟机里面的,并且每一个应用程序对应有一个单独的Dalvik虚拟机实例。Android应用程序中的Dalvik虚拟机实例实际上是从Zygote进程的地址空间拷贝而来的,这样就可以加快Android应用程序的启动速度。Dalvik虚拟机与Java虚拟机共享有差不多的特性,例如,它们都是解释执行,并且支持即时编译(JIT)、垃圾收集(GC)、Java本地方法调用(JNI)和Java远程调试协议(JDWP)等,差别在于两者执行的指令集是不一样的,并且前者的指令集是基本寄存器的,而后者的指令集是基于堆栈的。
本系列文章主要将Dalvik虚拟机的内存管理、垃圾收集、即时编译、Java本地调用、进程和线程管理等。理解Dalvik虚拟机的上述实现细节,有助于在运行时修改程序的行为,例如,拦截Java函数的调用
- Dalvik虚拟机概述
- Dalvik虚拟机的启动过程
- Dalvik虚拟机的运行过程
- JNI函数的注册过程
- Dalvik虚拟机进程
- Dalvik虚拟机线程
1.1 Dalvik虚拟机概述
Dalvik虚拟机由Dan Bornstein开发,名字来源于他的祖先曾经居住过的位于冰岛的同名小渔村
Dalvik虚拟机起源于Apache Harmony项目,后者是由Apache软件基金会主导的,目标是实现一个独立的、兼容JDK 5的虚拟机,并根据Apache License v2发布
Dalvik虚拟机与Java虚拟机的区别
- 基于堆栈的Java指令(1个字节)和基于寄存器的Dalvik指令(2、4或者6个字节)各有优劣
- 一般而言,执行同样的功能, Java虚拟机需要更多的指令(主要是load和store指令),而Dalvik虚拟机需要更多的指令空间
- 需要更多指令意味着要多占用CPU时间,而需要更多指令空间意味着指令缓冲(i-cache)更易失效
- Dalvik虚拟机使用dex(Dalvik Executable)格式的类文件,而Java虚拟机使用class格式的类文件
- 一个dex文件可以包含若干个类,而一个class文件只包括一个类
- 由于一个dex文件可以包含若干个类,因此它可以将各个类中重复的字符串只保存一次,从而节省了空间,适合在内存有限的移动设备使用
- 一般来说,包含有相同类的未压缩dex文件稍小于一个已经压缩的jar文件
Dex文件的优化
- 将invoke-virtual指令中的method index转换为vtable index – 加快虚函数调用速度
- 将get/put指令中的field index转换为byte offset – 加快实例成员变量访问速度
- 将boolean/byte/char/short变种的get/put指令统一转换为32位的get/put指令 – 减小VM解释器的大小,从而更有效地利用CPU的i-cache
- 将高频调用的函数,例如String.length,转换为inline函数 – 消除函数调用开销
- 移除空函数,例如Object.
<init>
-- 消除空函数调用 - 将可以预先计算的数据进行预处理,例如预先生成VM根据class name查询class的hash table – 节省Dex文件加载时间以及内存占用空间
- 将invoke-virtual指令中的method index转换为vtable index
Dex文件的优化时机
- VM在运行时即时优化,例如使用DexClassLoader动态加载dex文件时。这时候需要指定一个当前进程有写权限的用来保存odex的目录。
- APP安装时由具有root权限的installd优化。这时候优化产生的odex文件保存在特权目录/data/dalvik-cache中。
- 编译时优化。这时候编译出来的jar/apk里面的classes.dex被提取并且优化为classes.odex保存在原jar/apk所在目录,打包在system image中。
内存管理
- Java Object Heap
大小受限,16M/24M/32M/48M/… - Bitmap Memory(External Memroy):
大小计入Java Object Heap - Native Heap
大小不受限
Java Object Heap
- 用来分配Java对象。Dalvik虚拟机在启动的时候,可以通过-Xms和-Xmx选项来指定Java Object Heap的最小值和最大值。
- Java Object Heap的最小和最大默认值为2M和16M。但是厂商会根据手机的配置情况进行调整,例如,G1、Droid、Nexus One和Xoom的Java Object Heap的最大值分别为16M、24M、32M 和48M。
- 通过ActivityManager.getMemoryClass可以获得Dalvik虚拟机的Java Object Heap的最大值。
Bitmap Memory
- 用来处理图像。在HoneyComb之前,Bitmap Memory是在Native Heap中分配的,但是这部分内存同样计入Java Object Heap中。这就是为什么我们在调用BitmapFactory相关的接口来处理大图像时,会抛出一个OutOfMemoryError异常的原因:java.lang.OutOfMemoryError: bitmap size exceeds VM budget
- 在HoneyComb以及更高的版本中,Bitmap Memory就直接是在Java Object Heap中分配了,这样就可以直接接受GC的管理
Native Heap
- 在Native Code中使用malloc等分配出来的内存,这部分内存不受Java Object Heap的大小限制。
- 注意,不要因为Native Heap可以自由使用就滥用,因为滥用Native Heap会导致系统可用内存急剧减少,从而引发系统采取激进的措施来Kill掉某些进程,用来补充可用内存,这样会影响系统体验。
垃圾收集(GC)
-
Step 1: Mark,使用RootSet标记对象引用
-
Step 2: Sweep,回收没有被引用的对象
GingerBread之前 -
Stop-the-word,也就是垃圾收集线程在执行的时候,其它的线程都停止
-
Full heap collection,也就是一次收集完全部的垃圾
-
一次垃圾收集造成的程序中止时间通常都大于100ms
GingerBread之后 -
Cocurrent,也就是大多数情况下,垃圾收集线程与其它线程是并发执行的
-
Partial collection,也就是一次可能只收集一部分垃圾
-
一次垃圾收集造成的程序中止时间通常都小于5ms
即时编译(JIT)
-
从2.2开始支持JIT,并且是可选的,编译时通过WITH_JIT宏进行控制
-
基于执行路径(Executing Path)对热门的代码片断进行优化(Trace JIT),传统的Java虚拟机以Method为单位进行优化(Method JIT)
-
可以利用运行时信息进行激进优化,获得比静态编译语言更高的性能,如Lazy Unlocking机制
支持JDWP(Java Debug Wire Protocol)协议
- 每一个Dalvik虚拟机进程都都提供有一个端口来供调试器连接
- DDMS提供有一个转发端口8870,通过它可以同时调试多个Dalvik虚拟机进程
1.2 Dalvik虚拟机的启动过程
Dalvik虚拟机由Zygote进程启动,然后再复制到System Server进程和应用程序进程
startVM的过程中会创建一个JavaVMExt,并且该JavaVMExt关联有一个JNIInvokeInterface,Native Code通过它来访问Dalvik虚拟机
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*/
};
JNINativeInterface核心代码
std::unique_ptr<JavaVMExt> JavaVMExt::Create(Runtime* runtime,const RuntimeArgumentMap& runtime_options,std::string* error_msg) NO_THREAD_SAFETY_ANALYSIS {std::unique_ptr<JavaVMExt> java_vm(new JavaVMExt(runtime, runtime_options, error_msg));if (java_vm && java_vm->globals_.IsValid() && java_vm->weak_globals_.IsValid()) {return java_vm;}return nullptr;
}
虚拟机启动流程
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);jclass (*GetSuperclass)(JNIEnv*, jclass);jboolean (*IsAssignableFrom)(JNIEnv*, jclass, jclass);/* spec doesn't show jboolean parameter */jobject (*ToReflectedField)(JNIEnv*, jclass, jfieldID, jboolean);jint (*Throw)(JNIEnv*, jthrowable);jint (*ThrowNew)(JNIEnv *, jclass, const char *);jthrowable (*ExceptionOccurred)(JNIEnv*);void (*ExceptionDescribe)(JNIEnv*);void (*ExceptionClear)(JNIEnv*);void (*FatalError)(JNIEnv*, const char*);jint (*PushLocalFrame)(JNIEnv*, jint);jobject (*PopLocalFrame)(JNIEnv*, jobject);jobject (*NewGlobalRef)(JNIEnv*, jobject);void (*DeleteGlobalRef)(JNIEnv*, jobject);void (*DeleteLocalRef)(JNIEnv*, jobject);jboolean (*IsSameObject)(JNIEnv*, jobject, jobject);jobject (*NewLocalRef)(JNIEnv*, jobject);jint (*EnsureLocalCapacity)(JNIEnv*, jint);jobject (*AllocObject)(JNIEnv*, jclass);jobject (*NewObject)(JNIEnv*, jclass, jmethodID, ...);jobject (*NewObjectV)(JNIEnv*, jclass, jmethodID, va_list);jobject (*NewObjectA)(JNIEnv*, jclass, jmethodID, jvalue*);jclass (*GetObjectClass)(JNIEnv*, jobject);jboolean (*IsInstanceOf)(JNIEnv*, jobject, jclass);jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);jobject (*CallObjectMethod)(JNIEnv*, jobject, jmethodID, ...);jobject (*CallObjectMethodV)(JNIEnv*, jobject, jmethodID, va_list);jobject (*CallObjectMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);jboolean (*CallBooleanMethod)(JNIEnv*, jobject, jmethodID, ...);jboolean (*CallBooleanMethodV)(JNIEnv*, jobject, jmethodID, va_list);jboolean (*CallBooleanMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);jbyte (*CallByteMethod)(JNIEnv*, jobject, jmethodID, ...);jbyte (*CallByteMethodV)(JNIEnv*, jobject, jmethodID, va_list);jbyte (*CallByteMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);jchar (*CallCharMethod)(JNIEnv*, jobject, jmethodID, ...);jchar (*CallCharMethodV)(JNIEnv*, jobject, jmethodID, va_list);jchar (*CallCharMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);jshort (*CallShortMethod)(JNIEnv*, jobject, jmethodID, ...);jshort (*CallShortMethodV)(JNIEnv*, jobject, jmethodID, va_list);jshort (*CallShortMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);jint (*CallIntMethodV)(JNIEnv*, jobject, jmethodID, va_list);jint (*CallIntMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);jlong (*CallLongMethod)(JNIEnv*, jobject, jmethodID, ...);jlong (*CallLongMethodV)(JNIEnv*, jobject, jmethodID, va_list);jlong (*CallLongMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);jfloat (*CallFloatMethod)(JNIEnv*, jobject, jmethodID, ...);jfloat (*CallFloatMethodV)(JNIEnv*, jobject, jmethodID, va_list);jfloat (*CallFloatMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);jdouble (*CallDoubleMethod)(JNIEnv*, jobject, jmethodID, ...);jdouble (*CallDoubleMethodV)(JNIEnv*, jobject, jmethodID, va_list);jdouble (*CallDoubleMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);void (*CallVoidMethodV)(JNIEnv*, jobject, jmethodID, va_list);void (*CallVoidMethodA)(JNIEnv*, jobject, jmethodID, jvalue*);jobject (*CallNonvirtualObjectMethod)(JNIEnv*, jobject, jclass,jmethodID, ...);jobject (*CallNonvirtualObjectMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list);jobject (*CallNonvirtualObjectMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*);jboolean (*CallNonvirtualBooleanMethod)(JNIEnv*, jobject, jclass,jmethodID, ...);jboolean (*CallNonvirtualBooleanMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list);jboolean (*CallNonvirtualBooleanMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*);jbyte (*CallNonvirtualByteMethod)(JNIEnv*, jobject, jclass,jmethodID, ...);jbyte (*CallNonvirtualByteMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list);jbyte (*CallNonvirtualByteMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*);jchar (*CallNonvirtualCharMethod)(JNIEnv*, jobject, jclass,jmethodID, ...);jchar (*CallNonvirtualCharMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list);jchar (*CallNonvirtualCharMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*);jshort (*CallNonvirtualShortMethod)(JNIEnv*, jobject, jclass,jmethodID, ...);jshort (*CallNonvirtualShortMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list);jshort (*CallNonvirtualShortMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*);jint (*CallNonvirtualIntMethod)(JNIEnv*, jobject, jclass,jmethodID, ...);jint (*CallNonvirtualIntMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list);jint (*CallNonvirtualIntMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*);jlong (*CallNonvirtualLongMethod)(JNIEnv*, jobject, jclass,jmethodID, ...);jlong (*CallNonvirtualLongMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list);jlong (*CallNonvirtualLongMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*);jfloat (*CallNonvirtualFloatMethod)(JNIEnv*, jobject, jclass,jmethodID, ...);jfloat (*CallNonvirtualFloatMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list);jfloat (*CallNonvirtualFloatMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*);jdouble (*CallNonvirtualDoubleMethod)(JNIEnv*, jobject, jclass,jmethodID, ...);jdouble (*CallNonvirtualDoubleMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list);jdouble (*CallNonvirtualDoubleMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*);void (*CallNonvirtualVoidMethod)(JNIEnv*, jobject, jclass,jmethodID, ...);void (*CallNonvirtualVoidMethodV)(JNIEnv*, jobject, jclass,jmethodID, va_list);void (*CallNonvirtualVoidMethodA)(JNIEnv*, jobject, jclass,jmethodID, jvalue*);jfieldID (*GetFieldID)(JNIEnv*, jclass, const char*, const char*);jobject (*GetObjectField)(JNIEnv*, jobject, jfieldID);jboolean (*GetBooleanField)(JNIEnv*, jobject, jfieldID);jbyte (*GetByteField)(JNIEnv*, jobject, jfieldID);jchar (*GetCharField)(JNIEnv*, jobject, jfieldID);jshort (*GetShortField)(JNIEnv*, jobject, jfieldID);jint (*GetIntField)(JNIEnv*, jobject, jfieldID);jlong (*GetLongField)(JNIEnv*, jobject, jfieldID);jfloat (*GetFloatField)(JNIEnv*, jobject, jfieldID);jdouble (*GetDoubleField)(JNIEnv*, jobject, jfieldID);void (*SetObjectField)(JNIEnv*, jobject, jfieldID, jobject);void (*SetBooleanField)(JNIEnv*, jobject, jfieldID, jboolean);void (*SetByteField)(JNIEnv*, jobject, jfieldID, jbyte);void (*SetCharField)(JNIEnv*, jobject, jfieldID, jchar);void (*SetShortField)(JNIEnv*, jobject, jfieldID, jshort);void (*SetIntField)(JNIEnv*, jobject, jfieldID, jint);void (*SetLongField)(JNIEnv*, jobject, jfieldID, jlong);void (*SetFloatField)(JNIEnv*, jobject, jfieldID, jfloat);void (*SetDoubleField)(JNIEnv*, jobject, jfieldID, jdouble);jmethodID (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);jobject (*CallStaticObjectMethod)(JNIEnv*, jclass, jmethodID, ...);jobject (*CallStaticObjectMethodV)(JNIEnv*, jclass, jmethodID, va_list);jobject (*CallStaticObjectMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);jboolean (*CallStaticBooleanMethod)(JNIEnv*, jclass, jmethodID, ...);jboolean (*CallStaticBooleanMethodV)(JNIEnv*, jclass, jmethodID,va_list);jboolean (*CallStaticBooleanMethodA)(JNIEnv*, jclass, jmethodID,jvalue*);jbyte (*CallStaticByteMethod)(JNIEnv*, jclass, jmethodID, ...);jbyte (*CallStaticByteMethodV)(JNIEnv*, jclass, jmethodID, va_list);jbyte (*CallStaticByteMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);jchar (*CallStaticCharMethod)(JNIEnv*, jclass, jmethodID, ...);jchar (*CallStaticCharMethodV)(JNIEnv*, jclass, jmethodID, va_list);jchar (*CallStaticCharMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);jshort (*CallStaticShortMethod)(JNIEnv*, jclass, jmethodID, ...);jshort (*CallStaticShortMethodV)(JNIEnv*, jclass, jmethodID, va_list);jshort (*CallStaticShortMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);jint (*CallStaticIntMethod)(JNIEnv*, jclass, jmethodID, ...);jint (*CallStaticIntMethodV)(JNIEnv*, jclass, jmethodID, va_list);jint (*CallStaticIntMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);jlong (*CallStaticLongMethod)(JNIEnv*, jclass, jmethodID, ...);jlong (*CallStaticLongMethodV)(JNIEnv*, jclass, jmethodID, va_list);jlong (*CallStaticLongMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);jfloat (*CallStaticFloatMethod)(JNIEnv*, jclass, jmethodID, ...);jfloat (*CallStaticFloatMethodV)(JNIEnv*, jclass, jmethodID, va_list);jfloat (*CallStaticFloatMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);jdouble (*CallStaticDoubleMethod)(JNIEnv*, jclass, jmethodID, ...);jdouble (*CallStaticDoubleMethodV)(JNIEnv*, jclass, jmethodID, va_list);jdouble (*CallStaticDoubleMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);void (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...);void (*CallStaticVoidMethodV)(JNIEnv*, jclass, jmethodID, va_list);void (*CallStaticVoidMethodA)(JNIEnv*, jclass, jmethodID, jvalue*);jfieldID (*GetStaticFieldID)(JNIEnv*, jclass, const char*,const char*);jobject (*GetStaticObjectField)(JNIEnv*, jclass, jfieldID);jboolean (*GetStaticBooleanField)(JNIEnv*, jclass, jfieldID);jbyte (*GetStaticByteField)(JNIEnv*, jclass, jfieldID);jchar (*GetStaticCharField)(JNIEnv*, jclass, jfieldID);jshort (*GetStaticShortField)(JNIEnv*, jclass, jfieldID);jint (*GetStaticIntField)(JNIEnv*, jclass, jfieldID);jlong (*GetStaticLongField)(JNIEnv*, jclass, jfieldID);jfloat (*GetStaticFloatField)(JNIEnv*, jclass, jfieldID);jdouble (*GetStaticDoubleField)(JNIEnv*, jclass, jfieldID);void (*SetStaticObjectField)(JNIEnv*, jclass, jfieldID, jobject);void (*SetStaticBooleanField)(JNIEnv*, jclass, jfieldID, jboolean);void (*SetStaticByteField)(JNIEnv*, jclass, jfieldID, jbyte);void (*SetStaticCharField)(JNIEnv*, jclass, jfieldID, jchar);void (*SetStaticShortField)(JNIEnv*, jclass, jfieldID, jshort);void (*SetStaticIntField)(JNIEnv*, jclass, jfieldID, jint);void (*SetStaticLongField)(JNIEnv*, jclass, jfieldID, jlong);void (*SetStaticFloatField)(JNIEnv*, jclass, jfieldID, jfloat);void (*SetStaticDoubleField)(JNIEnv*, jclass, jfieldID, jdouble);jstring (*NewString)(JNIEnv*, const jchar*, jsize);jsize (*GetStringLength)(JNIEnv*, jstring);const jchar* (*GetStringChars)(JNIEnv*, jstring, jboolean*);void (*ReleaseStringChars)(JNIEnv*, jstring, const jchar*);jstring (*NewStringUTF)(JNIEnv*, const char*);jsize (*GetStringUTFLength)(JNIEnv*, jstring);/* JNI spec says this returns const jbyte*, but that's inconsistent */const char* (*GetStringUTFChars)(JNIEnv*, jstring, jboolean*);void (*ReleaseStringUTFChars)(JNIEnv*, jstring, const char*);jsize (*GetArrayLength)(JNIEnv*, jarray);jobjectArray (*NewObjectArray)(JNIEnv*, jsize, jclass, jobject);jobject (*GetObjectArrayElement)(JNIEnv*, jobjectArray, jsize);void (*SetObjectArrayElement)(JNIEnv*, jobjectArray, jsize, jobject);jbooleanArray (*NewBooleanArray)(JNIEnv*, jsize);jbyteArray (*NewByteArray)(JNIEnv*, jsize);jcharArray (*NewCharArray)(JNIEnv*, jsize);jshortArray (*NewShortArray)(JNIEnv*, jsize);jintArray (*NewIntArray)(JNIEnv*, jsize);jlongArray (*NewLongArray)(JNIEnv*, jsize);jfloatArray (*NewFloatArray)(JNIEnv*, jsize);jdoubleArray (*NewDoubleArray)(JNIEnv*, jsize);jboolean* (*GetBooleanArrayElements)(JNIEnv*, jbooleanArray, jboolean*);jbyte* (*GetByteArrayElements)(JNIEnv*, jbyteArray, jboolean*);jchar* (*GetCharArrayElements)(JNIEnv*, jcharArray, jboolean*);jshort* (*GetShortArrayElements)(JNIEnv*, jshortArray, jboolean*);jint* (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);jlong* (*GetLongArrayElements)(JNIEnv*, jlongArray, jboolean*);jfloat* (*GetFloatArrayElements)(JNIEnv*, jfloatArray, jboolean*);jdouble* (*GetDoubleArrayElements)(JNIEnv*, jdoubleArray, jboolean*);void (*ReleaseBooleanArrayElements)(JNIEnv*, jbooleanArray,jboolean*, jint);void (*ReleaseByteArrayElements)(JNIEnv*, jbyteArray,jbyte*, jint);void (*ReleaseCharArrayElements)(JNIEnv*, jcharArray,jchar*, jint);void (*ReleaseShortArrayElements)(JNIEnv*, jshortArray,jshort*, jint);void (*ReleaseIntArrayElements)(JNIEnv*, jintArray,jint*, jint);void (*ReleaseLongArrayElements)(JNIEnv*, jlongArray,jlong*, jint);void (*ReleaseFloatArrayElements)(JNIEnv*, jfloatArray,jfloat*, jint);void (*ReleaseDoubleArrayElements)(JNIEnv*, jdoubleArray,jdouble*, jint);void (*GetBooleanArrayRegion)(JNIEnv*, jbooleanArray,jsize, jsize, jboolean*);void (*GetByteArrayRegion)(JNIEnv*, jbyteArray,jsize, jsize, jbyte*);void (*GetCharArrayRegion)(JNIEnv*, jcharArray,jsize, jsize, jchar*);void (*GetShortArrayRegion)(JNIEnv*, jshortArray,jsize, jsize, jshort*);void (*GetIntArrayRegion)(JNIEnv*, jintArray,jsize, jsize, jint*);void (*GetLongArrayRegion)(JNIEnv*, jlongArray,jsize, jsize, jlong*);void (*GetFloatArrayRegion)(JNIEnv*, jfloatArray,jsize, jsize, jfloat*);void (*GetDoubleArrayRegion)(JNIEnv*, jdoubleArray,jsize, jsize, jdouble*);/* spec shows these without const; some jni.h do, some don't */void (*SetBooleanArrayRegion)(JNIEnv*, jbooleanArray,jsize, jsize, const jboolean*);void (*SetByteArrayRegion)(JNIEnv*, jbyteArray,jsize, jsize, const jbyte*);void (*SetCharArrayRegion)(JNIEnv*, jcharArray,jsize, jsize, const jchar*);void (*SetShortArrayRegion)(JNIEnv*, jshortArray,jsize, jsize, const jshort*);void (*SetIntArrayRegion)(JNIEnv*, jintArray,jsize, jsize, const jint*);void (*SetLongArrayRegion)(JNIEnv*, jlongArray,jsize, jsize, const jlong*);void (*SetFloatArrayRegion)(JNIEnv*, jfloatArray,jsize, jsize, const jfloat*);void (*SetDoubleArrayRegion)(JNIEnv*, jdoubleArray,jsize, jsize, const jdouble*);jint (*RegisterNatives)(JNIEnv*, jclass, const JNINativeMethod*,jint);jint (*UnregisterNatives)(JNIEnv*, jclass);jint (*MonitorEnter)(JNIEnv*, jobject);jint (*MonitorExit)(JNIEnv*, jobject);jint (*GetJavaVM)(JNIEnv*, JavaVM**);void (*GetStringRegion)(JNIEnv*, jstring, jsize, jsize, jchar*);void (*GetStringUTFRegion)(JNIEnv*, jstring, jsize, jsize, char*);void* (*GetPrimitiveArrayCritical)(JNIEnv*, jarray, jboolean*);void (*ReleasePrimitiveArrayCritical)(JNIEnv*, jarray, void*, jint);const jchar* (*GetStringCritical)(JNIEnv*, jstring, jboolean*);void (*ReleaseStringCritical)(JNIEnv*, jstring, const jchar*);jweak (*NewWeakGlobalRef)(JNIEnv*, jobject);void (*DeleteWeakGlobalRef)(JNIEnv*, jweak);jboolean (*ExceptionCheck)(JNIEnv*);jobject (*NewDirectByteBuffer)(JNIEnv*, void*, jlong);void* (*GetDirectBufferAddress)(JNIEnv*, jobject);jlong (*GetDirectBufferCapacity)(JNIEnv*, jobject);/* added in JNI 1.6 */jobjectRefType (*GetObjectRefType)(JNIEnv*, jobject);
};
startVM的过程中还会为当前线程关联有一个JNIEnvExt,并且该JNIEnvExt 关联有一个JNINativeInterface,Native Code通过它来调用Java函数或者访问Java对象
Dalvik虚拟机在Zygote进程启动的过程中,还会进一步预加载Java和Android核心类库以及系统资源
Dalvik虚拟机从Zygote进程复制到System Server进程之后,它们就通过COW(Copy On Write)机制共享同一个Dalvik虚拟机实例以及预加载类库和资源
Dalvik虚拟机从Zygote进程复制到应用程序进程之后,它们同样会通过COW(Copy On Write)机制共享同一个Dalvik虚拟机实例以及预加载类库和资源
Dalvik虚拟机的运行过程
- Dalvik虚拟机在Zygote进程中启动之后,就会以ZygoteInit.main为入口点开始运行
- Dalvik虚拟机从Zygote进程复制到System Server进程之后,就会以SystemServer.main为入口点开始运行
- Dalvik虚拟机Zygote进程复制到应用程序进程之后,就会以ActivityThread.main为入口点开始运行
- 上述入口点都是通过调用JNINativeInterface接口的成员函数CallStaticVoidMethod来进入的
J
JNINativeInterface->CallStaticVoidMethod对应的实现为CallStaticVoidMethodV-->InvokeWithVarArgs