一、简介
dalvik是google在其android智能手机操作系统中用的java虚拟机。借此讲一下我对虚拟机的基本理解吧。一切编程语言要想在计算机上运行必须翻译成机器码(这是废话)。java是一种半编译半解释型语言。半编译是指:java源代码,会经过javac命令变成 .class文件。半解释是指: .class文件被jvm解释的过程。也就是因为jvm的半解释才有了java的动态语言特性:反射和annotation。
二、类文件预处理
在半编译阶段,java源代码被编译,在.class文件中会有类信息和虚拟机指令。dalvik有自己的libdex库负责对.class进行处理。libdex主要对.class进行处理生成自己的dex文件。主要做的工作是,对虚拟机指令进行转换(dalvik是基于寄存器的,sun虚拟机是基于栈的),对类的静态数据进行归类、压缩。
三、类加载
在虚拟机启动时,根据输入的参数(一般有入口类(main函数所在的类)和jar包的路径),在classath路径中加载入口类,类加载过程是:虚拟机根据入口类的全称,去遍历classpath下的dex文件(dalvik第一次加载后会生成cache文件,供下次快速加载,所以第一次会很慢),获取入口类的信息,构建入口类的Class结构体,Class结构主要包含类的field、method、(anntation 和内部类dalvik放在native处理,没在Class结构体,这样为了节省内存)。另外在加载入口类之前,可能要加载,他所依赖的类,比如父类、Class类等,类被加载后一般会在classloader中保存,下次用可以直接取到。
- filed主要信息,filed的类型、变量名对static fiedl 还有可能有初始值(非static field在构造函数中赋初值,不保证每个类都有静态初始化块<clinit>方法,所以staitc filed初始值要单独处理)。
- method 主要有:方法签名、method Code(虚拟机指令)、exception等信息
四、类的初始化及resolve
在一个类的metod code被虚拟机解释器执行之前,一般要进行类的初始化,类初始化主要做:static变量的赋初值(如上所说)、及method code的预处理,因为在method code内都是静态的信息,比如:你要调一个类的某个方法,指令中可能只有类名和方法名的字符串信息,而不是这个这个method结构体的指针,如果要掉的类没有初始化,你可能还要初始化这个类。以及异常错误的处理,比如你调的方法不存在,要抛NoSuchMethodError。这步叫resolve。resolve过程也可以在解释器内做,因为你有可能初始化一个类,而不调用它的方法。dalvik是在第一次调一个方法时resolve的。
五、类的解释执行
在加载完入口类时,虚拟机会调用JNI(对虚拟机对外暴露的函数的封装,可以让java和C互相调用)的方法去执行,入口类的main方法,解释器首先获取此类的method结构体,获得method code一条一条解释执行。
常见的指令:
- const、const-string等:一般是把一个常量(int double short boolean char string ……),放入一个寄存器。
- add sub div xor or and ……:加减乘除、与或非等
- getfield putfield 、getstatic putstaic:在堆上获取相应对象的field值,对static可能在Class结构体内存放
- invokeXXX:调用某个方法,要在栈上保存当前frame信息(包括IP 及各寄存器值),push一个frame去解释另一个方法。方法调用是,要将这个方法的参数copy到新的frame 寄存器上。在被调用的方法结束时,在栈上pop出该frame,把方法返回值copy到调用frame的寄存器上。(这个可以有多种实现,dalvik是把返回值copy到全局的ret变量中,在用move_result指令来做到这一点)
- return :告诉解释器方法调用结束
- if if_eqz等:逻辑判断、还有swith case等也有专门指令
- new指令,new一个对象放在堆上
六、异常处理
首先明确一个概念,就是一个java的线程在dalvik内对应一个C线程,每个java线程都会有自己的执行栈。Exception的处理时,当解释器遇到Excepiton时,把这个异常对象放入Thread结构体保存,在解释某些有可能抛异常的指令时,去check,check到,就结束执行下一条指令,往下找catch,如果没有就一直往上抛,只到栈上没frame,虚拟机结束。
七、堆结构及GC
堆是虚拟机为了预存对象,而事先分配的一块大内存。对象在堆上一般要保存,其Class信息(属于某个class)和对象每个field的值。GC时,虚拟机遍历所有线程栈及全局变量(JNI全局reference、Stringpool等),对有引用对象进行mark,然后遍历堆进行swap。另外还牵扯finalize的执行及java reference机制等。
堆设计最大的麻烦在于,频繁的分配和释放对象可能导致内存碎片。一般做法是在GC后要进行一次堆整理,但对整理会改变对象的指针地址,可能导致其他对象引用一个无效的指针,所以一般要另外为每个对象对应一个定长的map,在引用对象上保存一个不变的映射值,在根据这个值找到对象。堆整理时,改变引用值。这种做法的坏处是浪费了内存,对JNI的getArrayElements方法不得不采用copy模式等。另一种做法是不进行堆整理,这样要用好的算法控制不至于产生过多的内存碎片。
分享到:
相关推荐
Moonbox(月光宝盒)是JVM-Sandbox生态下的,基于jvm-sandbox-repeater重新开发的一款流量回放平台产品。在jvm-sandbox-repeater基础上提供了更加丰富功能,同时便于线上部署和使用,更多对比参考。 使用场景 你...
nginx-upstream-jvm-route 支持nginx版本1.15 解决nginx: [emerg] invalid parameter "srun_id=tomcat1" 问题
JVM调优总结 -Xms -Xmx -Xmn -Xss
赠送jar包:metrics-jvm-3.1.5.jar; 赠送原API文档:metrics-jvm-3.1.5-javadoc.jar; 赠送源代码:metrics-jvm-3.1.5-sources.jar; 赠送Maven依赖信息文件:metrics-jvm-3.1.5.pom; 包含翻译后的API文档:...
jvm-full-gc调优-jvm-full-gc
赠送jar包:metrics-jvm-3.1.5.jar; 赠送原API文档:metrics-jvm-3.1.5-javadoc.jar; 赠送源代码:metrics-jvm-3.1.5-sources.jar; 赠送Maven依赖信息文件:metrics-jvm-3.1.5.pom; 包含翻译后的API文档:...
nginx-upstream-jvm-route-0.1.tar.gz 用来实现Nginx Tomcat 集群session复制的问题!
代码如下:failed to create jvm error code -4 这一般应是内存不够用所致,解决方法参考如下。 打开 Android Studio 安装目录下的bin目录,查找并打开文件 studio.exe.vmoptions,修改代码: 代码如下:-Xmx512m 为...
mini-jvm in rust实现jvm,jvm-rs-main.zip
JVM调优总结 -Xms -Xmx -Xmn -Xss JVM调优总结 -Xms -Xmx -Xmn -Xss
nginx_upstream_jvm_route 是一个 Nginx 的扩展模块,用来实现基于 Cookie 的 Session Sticky 的功能。 安装方法(进入Nginx源码目录): #patch -p0 < /path/to/this/directory/jvm_route.patch # ./configure -...
Jvm性能优化-JVM内存结构原理分析03
1.3Java运行的原理 2 1.4半编译半解释 3 1.5平台无关性 4 JVM内存模型 4 2.1 JVM规范 5 2.2 Sun JVM 8 2.3 SUN JVM内存管理(优化) 10 2.4 SUN JVM调优 13 2.5.JVM简单理解 16 2.5.1 Java栈 16 2.5.2 堆 16 2.5.3 ...
JVM,MIB,可通过SNMP协议监控JVM运行情况
官方离线安装包,测试可用。使用rpm -ivh [rpm完整包名] 进行安装
jvm性能调优-jvm内存模型和优化-performance-jvm-memorymodel-optimize
Jvm调优练习-jvm-tuning
JVM原理-jvm内存及相关图示
JVM-java-springboot-demo.zip
用于测试jvm gc调优-share-jvm-gc