JVM基础知识

2019-12-27  本文已影响0人  leap_

本文参考链接

运行时数据区

虚拟机栈:

栈的FILO符合java方法间的调用

栈帧:

每个方法在执行的时候会创建一个栈帧,栈帧是虚拟机栈的栈元素,是虚拟机用于进行方法调用和方法执行的数据结构;

当一个方法被执行时,会创建一个栈帧(当前栈帧),这个栈帧处于栈顶,在编译时期,栈帧中需要的操作数栈和局部变量表的大小已经完全确定,栈帧的内存不会在运行时受到影响;

动态连接:
      Person person = new Man();

在上述代码中,Person类是person对象的静态类型,Man类是person对象的实际类型,静态类型和实际类型都可以发生改变,通过强转改变静态类型,重新new一个对象改变实际类型,所以静态类型的确定是在编译期,实际类型的确定在代码运行时;
重载是通过静态类型来判断执行版本,这个称为静态分派
重写是通过实际类型来判断执行版本,这个称为动态分派

栈帧数据的通信:

方法和方法之间的数据交互是通过使用同一块内存完成的,即栈帧A的本地变量表可能是栈帧B的操作数栈,同一块内存对于不同的栈帧是不同的角色;

虚拟机对于栈的优化:方法内联

方法A调用方法B,将方法B的代码作为方法A的一部分来执行,从而避免创建栈帧,减少栈内存的消耗

类加载过程

深入理解Java虚拟机插图

上面的类加载过程中,加载,验证,准备,初始化,卸载,这五个步骤的顺序是确定的,必须按照这个顺序进行,解析阶段在一些情况下可以在初始化之后进行;

加载:

获取二进制字节流这一步是开发者在类加载中可控性最强的阶段(通过自定义classLoader)

验证(连接第一步):

目的:确保Class文件的字节流符合当前虚拟机的要求,不会对虚拟机的安全产生威胁;class字节码文件不一定通过.java源文件编译来,(动态代理原理中是通过特定接口生成,还可以通过网络<Applet>,其他文件<JSP>等方式生成class字节码),所以,通过其他途径生成的字节码文件,可以做java语言做不到的事情,这些可能导致系统的奔溃;

验证内容:

准备(连接第二步):

为类的静态变量分配内存(方法区),并且初始化静态变量为0/false/null;

注意:这里是将static变量分配到方法区,而不是实例变量,实例变量是在对象创建的时候分配在中的;

解析(连接第三步):

将常量池中的符号引用转为直接引用

常量池种类:

  1. class文件常量池:编译后,class常量池存放 字面量符号引用
  2. 全局字符串常量池:类加载阶段,在堆中创建字符串对象,对象的真实引用放入全局常量池,1.7以后,全局字符串常量池被移动到了堆内;
  3. 运行时常量池:类加载阶段(二进制字节码代表的静态数据结构转为方法区的运行时数据结构),将class常量池的符号引用放入运行时常量池, 解析阶段,将运行时常量池的符号引用转为和全局常量池一致的直接引用
  4. 基本类型包装类对象常量池:

初始化:

执行类构造器clinit(),初始化类变量和其他资源,在准备阶段,我们为类变量在方法区分配了内存,并且将类变量置为0,false,/null ,在初始化阶段会将类变量设置为代码中的实际值,如果类中有静态代码块也会在这一阶段执行;

注意:

对象创建过程

对象内存布局

对象访问

句柄访问:
直接访问:

可达性分析法——判断对象是否需要回收

可达性分析法:

GCRoot对象:
public class OOM {
    
    private int rootConstant = 1000; // 方法区常量对象GCRoot
    private static Object rootStatic = new Object(); // 方法区静态对象GCRoot
    private Object nonRoot = new Object(); // 类实例对象,非GCRoot

    public void test (){
        Object rootJavaStack = new Object();  //  虚拟机栈引用的对象GCRoot

        // 可达,不会回收
        Object obj0 = rootConstant;
        Object obj1 = rootStatic;
        Object obj2 = rootJavaStack;
        // 不可达,回收
        Object obj3 = nonRoot;
    }
    
}
Java引用类型:
生存还是死亡:

其实在被认定了不可达以后,还需要经过两次标记筛选;

垃圾回收算法

复制算法:

复制算法
特点:

标记清除:

标记清除算法
特点:

标记整理:

标记整理算法
特点:

分代收集算法:

将内存分为新时代和老年代,新生代再分为Eden和Survivor(from to)区


GC发生的条件:空间不够(Eden/老年代满了,继续放对象时,会触发GC)

收集行为 算法 特点 发生时刻
新生代 Minor GC 复制算法 回收频率高,对象存活率低 Eden区无可分配内存
老年代 Full GC 标记整理/ 标记清除 回收频率低,对象存活率高 老年代无可分配内存

垃圾收集器()
吞吐量 = 业务线程运行时间/总CPU时间

常见的七种垃圾收集器
垃圾收集器 收集器类型 收集对象 算法
Serial 单线程 新生代 复制
ParNew 并行的多线程 新生代 复制
Parallel Scavenge 并行的多线程 新生代 复制
Serial Old 单线程 老年代 标记整理
Parallel Old 并行的多线程 老年代 标记整理
CMS 并行并发的收集器 老年代 标记清除
G1 并发并行的收集器 新生代&老年代 复制+标记整理
单线程垃圾收集器工作示意图 多线程垃圾收集器工作示意图
CMS垃圾收集器:Concurrent Mark Sweep
步骤:
CMS收集器工作示意图
特点:
G1收集器:Garbage First

最新、技术最前沿的垃圾收集器

步骤:
G1收集器工作示意图
特点:
上一篇 下一篇

猜你喜欢

热点阅读