目录
3)程序计数器(Program Counter Register)
一、类加载器
1)类加载器
类加载器将class文件字节码内容加载到内存中,并将这些内容转换为方法区中的运行时数据结构。
2)类加载器分类
①启动类加载器(BootstrapClassLoader):虚拟机自带的加载器,用于加载$JAVA_HOME/jre/lib/rt.jar包内的class文件。rt.jar是Java基础类库,包含Java运行环境所需的基础类。
②拓展类加载器(ExtClassLoader):虚拟机自带的加载器,由Java语言实现,用于加载$JAVA_HOME/jre/lib/ext/**.jar目录下的class文件
③应用程序加载器(AppClassLoader):虚拟机自带的加载器,用于加载当前应用的classpath的所有类,也就是我们自己写的那些Java代码。
④用户自定义加载器:通过继承Java.lang.ClassLoader抽象类自定义一个类加载器。
3)双亲委派机制
当一个类收到了加载请求,他会首先把这个请求委派给他的父类去完成且每一层次的类皆是如此(AppClassLoader委派给它的父类ExtClassLoader去加载,ExtClassLoader又委派给它的父类BootstrapClassLoader去加载。)只有当父类加载器反馈无法完成(它的加载路径下没有找到所需加载的Class)时,子类加载器才会尝试自己加载。
优点:由于无论加载器加载那个类,最终都是委托给最顶层的加载器进行加载,这样就能保证我们自定义的Java类不会污染JDK自带的类。这种保护机制也称为沙箱安全机制。
4)类加载步骤
①加载(Loading)通过类的全类名取得二进制字节流,将这个二进制流代表的静态存储结构转化为方法区的运行时数据结构,然后在内存中生成一个代表这个类的Java.lang.Class对象,作为方法区中这个类的各种数据额访问入口。
②链接(Linking)该过程主要完成验证、静态变量初始化默认值和解析符号。
链接分为三个阶段:验证(Verification)、准备(Preparation)和解析(Resolution)
I. 验证阶段用于确保加载的Class文件的字节流包含的信息是符合虚拟机要求,保证其正确性合法性;
II. 准备阶段为类变量(static修饰的变量)分配内存并根据对象类型设置相应的默认初始值(int为0,integer为null)。
III. 解析阶段用于将符号引用转换为直接引用。
③初始化(Initialization)为所有的静态变量赋值以及静态代码块中的操作。
I. 初始化阶段就是执行类的构造器方法<clinit>()的过程
II. clinit不是类的构造器,不需要自己定义,是javac编译器自动搜集类中的所有类变量的赋值动作和静态代码块中的语言合并而来
III. 一个类不包含类变量(静态变量)和静态代码块,那么它的字节码中就不会有构造器方法<clinit>()
IV. 静态变量(类变量)在类加载过程的初始化阶段才会被赋值,常量在编译的时候就会被分配具体值
二、JVM内存模型
1)堆(Heap)
2)方法区(Method Area)
3)程序计数器(Program Counter Register)
①程序计数器又称PC寄存器,每个线程都有一个程序计数器,是线程私有的,是一块较小的内存空间。
②程序计数器是一个指针,指向了方法区中的方法字节码,用来存储指向下一条指令的地址,即将要执行的指令代码
③如果执行的是一个Native方法,则计数器值为undefied
④可以在cmd窗口中输入javap -c xxx.class来查看字节码
4)虚拟机栈(VM Stack)
①虚拟机栈也称为Java栈,每个线程在创建的时候都会创建一个虚拟机栈,其内部保存一个个栈帧(Stack Frame)。每个方法被执行的时候,Java虚拟机都会同步创建一个栈帧。
I. Java虚拟机是线程私有的,它的生命周期与线程相同;
II. 每个方法从被调用到执行完毕,对应着栈帧在虚拟机栈入栈到出栈。
②栈帧包括局部变量表(Local Variables)、操作数栈(Operand Stack)、动态链接(Dynamic Linking)、方法返回地址(Return Address)和一些附加信息。
I. 局部变量表:LocalVariableTable是一个数字数组,用于存储方法参数和方法内的局部变量,可以通过javap -v **.class查看。
II. 操作数栈:每一个独立的栈帧中除了包含局部变量表外,还包含一个FILO的操作数栈,用于保存计算过程中的中间结果,同时作为计算过程中变量临时的存储空间。
III. 动态链接:在Java源文件被编译为字节码文件时,所有的变量和方法引用都将作为符号引用保存在class文件的常量池里,动态链接的作用就是为了将这些符号引用转化为调用方法直接引用。
IV. 方法返回地址:存放调用该方法的pc寄存器的值。
i. 方法正常退出时,调用者的pc寄存器的值作为返回地址,即调用该方法的指令的下一条指令地址;
ii. 出现未处理异常,非正常退出时,返回地址需要通过异常表确定。
V. 一些附加信息:如对程序调式提供的支持信息
③Java栈特点
I. 方法中定义的基本类型变量,对象的引用变量都在方法的栈内存中分配;
II. 栈内存特点,数据一执行完毕,变量会立即释放,节约内存空间。
III. 栈内存中的数据,没有默认初始化值,需要手动设置
④虚拟机栈大小调整
可以使用-Xss(ThreadStackSize)设置虚拟机的大小
5)本地方法栈(Native Method Stack)
①本地方法栈:用于管理本地方法的调用
②本地方法接口(Native Interface):作用是融合不同的编程语言为Java所用,它的初衷是融合C/C++程序,于是就在内存中专门开辟了一块区域处理标记为native的代码。