Java虚拟机主要模块详解图:
1.类装载器
*根类加载器(bootstrap class loader)
它用来加载 Java 的核心类,是用原生代码来实现的,并不继承自 java.lang.ClassLoader
*扩展类加载器(extensions class loader)
它负责加载JRE的扩展目录,lib/ext或者由java.ext.dirs系统属性指定的目录中的JAR包的类。
*系统类加载器(system class loader)
被称为系统(也称为应用)类加载器,它负责在JVM启动时加载来自Java命令的-classpath选项、java.class.path系统属性,或者CLASSPATH换将变量所指定的JAR包和类路径。程序可以通过ClassLoader的静态方法getSystemClassLoader()来获取系统类加载器。如果没有特别指定,则用户自定义的类加载器都以此类加载器作为父加载器。由Java语言实现,父类加载器为ExtClassLoader。
*用户类加载器(Customed clsss loader)
JVM的类加载机制主要有如下3种:
**全盘负责:所谓全盘负责,就是当一个类加载器负责加载某个Class时,该Class所依赖和引用其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入。
**双亲委派:所谓的双亲委派,则是先让父类加载器试图加载该Class,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类。通俗的讲,就是某个特定的类加载器在接到加载类的请求时,首先将加载任务委托给父加载器,依次递归,如果父加载器可以完成类加载任务,就成功返回;只有父加载器无法完成此加载任务时,才自己去加载。
**缓存机制:缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区中搜寻该Class,只有当缓存区中不存在该Class对象时,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓冲区中。这就是为很么修改了Class后,必须重新启动JVM,程序所做的修改才会生效的原因。
2.运行时数据区(内存结构)
*方法区
方法区(Method Area)与 Java 堆一样,是所有线程共享的内存区域。静态变量 + 常量 + 类信息(构造方法/接口定义) + 运行时常量池存在方法区中 。
方法区里存储着class文件信息和动态常量池,class文件的信息包括类信息和静态常量池。
*堆内存 (先进后出)
新生区(伊甸区、幸存0区、幸存1区)
养老区
永久存储区
*java栈
栈也叫栈内存,主管Java程序的运行,是在线程创建时创建,它的生命期是跟随线程的生命期,线程结束栈内存也就释放,对于栈来说不存在垃圾回收问题,只要线程一结束该栈就Over,生命周期和线程一致,是线程私有的。
*本地方法栈
本地方法栈(Native Method Stacks)与 Java 虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行 Java 方法(也就是字节码)服务,而本地方法栈则是
为虚拟机使用到的 Native 方法服务。
Navtive 方法是 Java 通过 JNI 直接调用本地 C/C++ 库,可以认为是 Native 方法相当于 C/C++ 暴露给 Java 的一个接口,Java 通过调用这个接口从而调用到 C/C++ 方法。当线程调用 Java 方法时,虚拟机会创建一个栈帧并压入 Java 虚拟机栈。然而当它调用的是 native 方法时,虚拟机会保持 Java 虚拟机栈不变,也不会向 Java 虚拟机栈压入新的栈帧,虚拟机只是简单地动态连接并直接调用指定的 native 方法。
*程序计数器 (不会溢出)
程序计数器,可以看做是当前线程执行的字节码的 行号指示器 ,简单的理解为,是程序计数器保证了程序的正常执行。
3.执行引擎
*即时编译器
*垃圾收集模块GC( GC的作用区域:方法区和堆 )
标记处理法:
finalize()
生态计数法:
新生态
老生态
永生态
4.本地方法库接口--本地方法库
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
类加载机制
JVM把class文件加载到内存,并对数据进行校验、解析和初始化,最终形成JVM可以直接使用的java类型的全过程。
1.加载
将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区中的运行时数据结构,在堆中生成一个代表这个类的java.lang.Class对象,作为方法区类数据的访问入口,这个过程需要类加载器参与。
2.连接
将java类的二进制代码合并到JVM的运行状态之中的过程
a.验证
确保加载的类信息符合JVM规范,没有安全方面的问题
b.准备
正式为类变量(static变量)分配内存并设置类变量初始值的阶段,这些内存都将在方法区中进行分配
c.解析
虚拟机常量池的符号引用替换为字节引用过程
3.初始化
初始化阶段是执行类构造器<clinit>()方法的过程。类构造器<clinit>()方法是由编译器自动收藏类中的所有类变量的赋值动作和静态语句块(static块)中的语句合并产生
当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化
虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确加锁和同步
当范围一个Java类的静态域时,只有真正声名这个域的类才会被初始化
4.使用
5.卸载