JAVA执行流程和内存模型
执行流程
- java程序执行分两步
- 第一步:java源码(.java文件)通过编译器(javac.exe)编译成JVM文件(.class文件)。
- 第二部:将JVM文件通过java.exe执行,输出结果。
java源文件–(javac.exe)–>JVM文件–(java.exe)–>结果。
JVM至关重要,其向上屏蔽了操作系统,也是java跨平台的关键。
编译和执行的三个重要机制
-
java编译机制:
- 分析和输入到符号表
- 注解处理
- 语义分析和生成class文件
最后生成的class文件由以下部分组成:
1、结构信息:包括class文件格式版本号及各部分的数量与大小信息。
2、元数据:对应java源码中声明与常量的信息。包含类/继承的超累/实现的接口的声明信息、域与方法声明信息和常量池。
3、方法信息:对应java源码中语句和表达式对应的信息。包含字节码、异常处理器表、求值栈与局部变量区大小、求值栈的类型记录、调试符号信息。
-
类加载机制
JVM类加载机制是通过ClassLoader及其子类来完成的。
1、Bootstrap ClassLoader 负责加载@JAVA_HOME中jre/lib/rt.jar里面所有的class,由C++实现,不是ClassLoader子类。
2、Extension ClassLoader负责加载java平台中扩展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目录下的jar包。
3、App ClassLoader负责记载classpath中指定的jar包及目录中class
4、Custom ClassLoader属于应用程序根据自身需要自定义的ClassLoader,如tomcat、jboss都会根据j2ee规范自行实现ClassLoader。
加载过程先检查类是否已加载,检查顺序自底向上,从Custom ClassLoader 到Bootstrap ClassLoader逐层检查,只要某个ClassLoader已加载就视为已加载此类,保证此类所有ClassLoader加载一次。而加载顺序是自顶向下的,也就是由上层逐层尝试加载此类
虚拟机把描述类的数据从字节码加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的java类型。
- 类执行机制
JVM是基于堆栈的虚拟机JVM为每个新创建的线程都分配一个堆栈,也就是说,对于一个java程序员来说,程序的运行就是对堆栈的操作来完成的。堆栈以帧为单位保存线程的状态。JVM对堆栈只有进行两种操作:以帧为单位的压栈和出栈操作。
JVM执行class字节码,线程创建后都会产生程序计数器和栈,程序计数器存放下一条要执行的指令在方法内的偏移量,栈中存放一个个栈帧,每个栈帧对应着每个方法的每次调用,而栈帧又是有局部变量区和操作数据栈两部分组成,局部变量区用于存放方法中的局部变量和参数,操作数栈中用于存放方法执行过程中产生的中间结果。
执行引擎找到main()方法入口,执行其中的字节码指令。
内存模型
- 模型图
模型各区域介绍
- 程序计数器
可以看作当前线程所执行的字节码的行号计数器(当前线程,所以是线程私有的),字节码解释器工作时需要通过改变这个程序计数器的值来需要通过改变这个程序计数器的值来选取下一条需要执行的字节码指令,循环、跳转、异常、线程回复等基础功能都需要依赖他完成。
- VM栈
描述的时java方法执行的内存模型:每个方法再执行时都会创建一个栈帧,用于存储局部变量表,操作数据栈,动态连接和方法出口等信息。每一个方法从调用到执行完成的过程,就对应一个栈帧从虚拟机栈入栈到出栈的过程。
- 本地方法栈
虚拟机执行的时java方法(也就是字节码)服务,而本地方法栈则为虚拟机所使用到的Native方法服务。
- 堆
是被所有线程贡献的一块区域,再虚拟机创建时创建,唯一的目的时存放对象实例,也是垃圾收集器管理的主要区域。
- 方法区
所有线程共享的区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
方法区中有运行时常量池。
- 总结
JVM的功能模块主要包括类加载器、执行引擎和垃圾回收系统。