Java代码执行流程:
Java源码通过编译器编译成字节码文件,字节码文件去Java虚拟机执行,执行过程,首先是类加载器,然后字节码校验器,然后执行引擎(包括翻译字节码解析执行,和JIT即时编译器编译执行),然后再去操作操作系统。
JVM架构模型:
hotspot是基于栈的指令集架构,指令集更小,指令多,以零地址指令为主,不需要地址指令。执行性能比寄存器稍微差一些,不需要硬件支持,可移植性好,更好实现跨平台。
还有一种基于寄存器的指令集架构,指令集大,指令少,完全依赖硬件,可移植性差,但性能优秀,执行高效。
JVM的生命周期:
虚拟机的启动:自定义类通过系统类加载器加载到内存中。虚拟机启动是通过引导类加载器(object类)创建的一个初始类完成。
虚拟机的执行:执行程序的过程,实际上就是在执行一个叫Java虚拟机的进程。
虚拟机的退出:程序正常执行结束,执行遇到异常,操作系统出现错误导致进程终止,线程调用runtime类或system类exit方法。
Runtime类模式:
运行时数据区对应的是Runtime运行时环境,这个类是饿汉式单例的(保证线程安全),一来就创建好的是饿汉式,用的时候才创建是懒汉式(可以理解为饿了一开始就吃和有需要才吃)
JIT即时编译器
寻找并加载热点数据,缓存到方法区的CodeCache,程序启动要加载字节码,如果用于加载全部数据,则字节码全部转换成JIT的机器指令过程耗费大量时间。
类加载器子系统
如果自己手写一个Java虚拟机,需要哪些结构呢?
类加载器子系统和执行引擎
类加载器和类加载过程
负责从文件系统或网络加载class文件,文件开头要有特定标识(16进制cafebaby);
类加载器只负责class文件加载,至于是否可运行,由ExecutionEngine执行引擎决定;
加载的类信息存放于方法区的内存空间,方法区还会存放运行时常量池等信息。
loading(加载阶段)
通过一个类的全限定名,获取二进制字节流;
将字节流静态存储结构转换为方法区运行时数据结构;
在内存中生成一个代表这个类的Java.lang.Class对象(生成大的class实例),作为方法区这个类的各种数据访问入口
linking(链接阶段)
验证(verify):
确保class文件字节流信息符合虚拟机要求,保证被加载类的正确性,主要四种验证:文件格式验证,元数据验证,字节码验证,符号引用验证。
准备(prepare):
为类变量分配内存,并设置类变量默认初始值(0,0.0,-u0000,false,Null)
不包含用final修饰的static,因为final编译时就分配了,准备阶段会显式初始化,不会为实例变量分配初始化,因为还没创建对象。。。
解析(resolve):
将常量池中的符号引用转换成直接引用的过程
解析操作往往会伴随JVM在执行完初始化之后再进行
Initialization(初始化阶段)
初始化阶段就是执行类构造器方法()的过程
构造器方法中指令按语句在源文件中出现的顺序执行
子类必须等待父类初始化加载完成之后才会进行初始化
虚拟机必须保证一个类的()方法在多线程下被同步加锁(静态代码块只执行一次,即使之后再创建线程也不会执行静态块)
类加载器的分类
JVM支持两种类的加载器:引导类加载器和自定义加载器(扩展类和系统类加载器间接继承ClassLoader)
四者之间不是继承关系
启动类加载器(Bootstrap ClassLoader)
C/C++实现
用来加载Java核心类库,提供JVM自身需要的类
并不继承java.lang.ClassLoader,没有父类加载器
加载扩展类和应用程序类加载器,并指定为他们的父类加载器
安全考虑,只加载包名为java,javax,sun等开头的类
扩展类加载器(ExtClassLoader)
Java语言编写
父类加载器为启动类加载器
加载核心包之外的扩展类的包
应用程序类加载器(AppClassLoader)
java编写
是程序中默认的类加载器