首页 > 代码库 > 浅谈JVM及原理
浅谈JVM及原理
1、什么是JVM ?
JVM, 中文名是Java虚拟机, 正如它的名字, 是一个虚拟机器,来模拟通用的物理机。 JVM是一个标准,一套规范, 规定了.class文件在其内部运行的相关标准和规范。 及其相关的内部构成。 比如:所有的JVM都是基于栈结构的运行方式。那么不符合这种要求的,不算是JVM, 如Android中所使用的Dalvik 虚拟机就不能称作是JAVA 虚拟机, 因为它是基于寄存器(最新的Android系统据说已经放弃了Dalvik VM, 而是使用ART)。
JVM相关的产品有很多, 通常最有名的莫过于现在Oracle公司所有的HotSpot 虚拟机。因此, 这里讨论的都是HotSpot虚拟机, 如果没有特别说明。
2、类加载?
3、类加载的具体过程?
被java编译器(不仅限于, 还有其他任何的可以编辑成为.class的编译器)编译过的.class文件(可能是以jar、war、jsp等形式), 经过类加载器加载 、 验证、准备、解析、初始化之后, 才可以被使用。基本的过程如下:
- 加载: 首先,通过一个类的全类名来获取此类的二进制字节流。其次,将类中所代表的静态存储结构转换为运行时数据结构, 最后,生成一个代表加载的类的java.lang.Class对象, 作为方法区这个类的所有数据的访问入口。加载完成之后, 虚拟机外部的二进制静态数据结构就转换成了虚拟机所需要的结构存储在方法区中(至于如何转换, 则由具体虚拟机自己定义实现), 而所生成的Class对象, 则存放在方法区中, 用来作为程序访问方法区中数据的外部接口。
- 验证:其目的就是保证加载进来的.class文件不会危害到虚拟机本身, 且内容符合当前虚拟机规范要求。主要验证的内容大致有:文件格式、元数据验证、字节码验证、符号引用验证。其中文件格式验证, 主要确保符合class文件格式规范(如文本后缀为.class的文件将验证不通过), 以及主次版本号, 验证是否当前JVM可以处理等。元数据验证,主要验证编译后的字节码描述信息是否符合java语法规范。字节码验证, 其最为复杂, 主要通过控制流和数据流确定语义是否合法、符合逻辑。符号引用验证,可以看做是除自身以外(常量池中各种引用符号)的信息匹配校验,如通过持有的引用能否找到对应的实例。
- 准备:正式为类变量分配内存,并设置类变量的初始值。这些变量都会在方法区中进行分配。
- 解析:将常量池内的符号引用替换为直接引用的过程。主要针对类或接口、字段、类方法、接口方法、方法类型、方法句柄等。
- 初始化:加载的最后阶段, 程序真正运行的开始。
4、java运行时数据区 ?
- 程序计数器 (PC):可以看做是当前线程执行字节码的行号指示器。字节码解释器工作的时候就是通过这个计数器的值来选取下一条需要执行的字节码指令, 分支, 循环、跳转、异常处理、线程恢复等基础功能依赖计数器完成。
- 虚拟机栈:和计数器一样, 也是线程私有的,生命周期同线程一致。每个方法在执行时,都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接、方法出口等信息。方法调入则入栈, 方法执行完则出站。局部变量表存储各种基本类型数据(java的8种,其中long,double占用2个局部变量控件,其余数据占用1个)、对象引用(reference类型)。局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时, 这个方法需要在帧中分配多大的局部变量空间是完全确定的。在方法运行期间是不会改变局部变量表的大小的。
- 本地方法栈:此栈和JVM栈作用非常类似, 不同在于本地方法栈为虚拟机使用到的Native方法服务, 而JVM栈则是为Java执行的方法服务。Sun HotSpot虚拟机, 直接把本地方法栈和虚拟机栈合二为一。本地方法栈也会抛出StackOverFlowError和OutOfMemoryError异常。
- Java堆:是JVM管理内存中最大的一块。被所有线程共享一块区域。堆是GC垃圾收集器管理的主要区域。从内存回收角度看, java堆被分为新生代、老年代, 再细致一点有其他的划分。这些目的主要就是更快的分配和回收内存。
方法区:和java堆相同, 线程共享区域, 用来存储已被虚拟机加载的类信息, 常量、静态变量、即时编译器编译后的代码等数据。有人称作此方法区为“永久带”, 本质上不等价,只是HotSpot VM将GC分代收集扩展到了方法区,这样HotSpot的垃圾收集器管理方法区和管理java堆一样(优点:不用专门为方法区写一套垃圾收集器, 缺点:容易导致内存溢出)。官方现在拥也有放弃永久带并改为采用Native Memory来实现方法区的计划,目前已经发布的JDK7中的HotSpot中, 已经将原本放在方法区中的字符串常量池移出了。
运行时常量池:是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述外,还有一项就是常量池, 用于存放编译期间生成的各种字面量和符号引用 ,这部分内容在类加载后进入方法区的运行时常量池中存放。
5、垃圾收集?
浅谈JVM及原理