JVM个人简记

1、JDK/JRE/JVM关系

在这里插入图片描述

2、源码到类文件

在这里插入图片描述

3、Javac编译过程

在这里插入图片描述

4、class文件16进制

在这里插入图片描述

5、class文件官方规范定义的格式

在这里插入图片描述

6、类加载机制:类文件到虚拟机(类加载子系统)

所谓类装载机制就是:

虚拟机把Class文件加载到内存
并对数据进行校验,转换解析和初始化
形成可以虚拟机直接使用的Java类型,即java.lang.Class

6.1、加载

在这里插入图片描述

6.2、链接

验证、准备、解析

6.3、初始化

1.为类的静态变量赋值,然后执行类的初始化(static)语句

2.初始化的详细过程:

1.如果类还没有被加载和链接,那就先进行加载和链接
2.如果类存在父类,并且父类还没有初始化,那就先初始化直接父类
3.如果类中存在初始化语句,顺序执行初始化语句

3.类的初始化阶段是执行类构造器方法clinit()的过程

1.类加载就是执行Java程序编译之后在字节码文件中生成的clinit()方法(称之为类构造器),clinit()方法由静态变量和静态代码块组成。
2.子类的加载首先需要先加载父类,如果父类为接口。则不会调用父类的clinit方法。一个类中可以没有clinit方法。
3.clinit方法中的执行顺序为:父类静态变量初始化,父类静态代码块,子类静态变量初始化,子类静态代码块。
4.clinit()方法只执行一次。

4.在准备阶段,变量已经赋过一次系统要求的初始值,而在初始化阶段,则根据程序员通过程序制定的主观计划去初始化类变量和其他资源,或者可以从另外一个角度来表达:初始化阶段是执行类构造器<clinit>()方法的过程。
1).<clinit>()方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static{}块)中的语句合并产生的,编译器收集的顺序是由语句在源文件中出现的顺序所决定的,静态语句块中只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以赋值,但是不能访问。如下代码:

public class Test{
    static{
        i=0;//给变量赋值可以正常编译通过
        System.out.print(i);//这句编译器会提示"非法向前引用"
    }
    static int i=1;
}

2).虚拟机会保证在子类的<clinit>()方法执行之前,父类的<clinit>()方法已经执行完毕。 因此在虚拟机中第一个被执行的<clinit>()方法的类肯定是java.lang.Object。由于父类的<clinit>()方法先执行,也就意味着父类中定义的静态语句块要优先于子类的变量赋值操作,如下代码中,字段B的值将会是2而不是1。

static class Parent{
	 public static int A=1;

	 static{
	     A=2;
	 }
	 static class Sub extends Parent{
	     public static int B=A;
	 }
	 public static void main(String[]args){
	     System.out.println(Sub.B);
    }
}

3).接口中不能使用静态语句块,但仍然有变量初始化的赋值操作,因此接口与类一样都会生成<clinit>()方法。 但接口与类不同的是,执行接口的<clinit>()方法不需要先执行父接口的<clinit>()方法。 只有当父接口中定义的变量使用时,父接口才会初始化。 另外,接口的实现类在初始化时也一样不会执行接口的<clinit>()方法。注意:接口中的属性都是static final类型的常量,因此在准备阶段就已经初始化。

4).< clinit >方法是在类加载过程中执行的,而< init >是在对象实例化执行的,所以< clinit >一定比< init >先执行。所以整个顺序为: 1.父类静态变量初始化 2.父类静态语句块 3.子类静态变量初始化 4.子类静态语句块 5.父类变量初始化块 6.父类语句块 7.父类构造函数 8.子类变量初始化块 9.子类语句块 10.子类构造函数

7、JVM运行时数据区

在这里插入图片描述
在这里插入图片描述

7.1、方法区

JDK1.7:PermSpace —>永久代

JDK1.8:MetaSpace —>元空间

在这里插入图片描述
在这里插入图片描述

7.2、堆

在这里插入图片描述

7.3、Java虚拟机栈

JDK1.5之后,默认大小为1M

栈溢出报错StackOverflowError

一个线程的创建代表的是一个栈

每个方法被当前线程调用了,就代表一个栈帧

在这里插入图片描述

示例方法:

在这里插入图片描述

Javap命令反编译后的字节码指令

在这里插入图片描述

指令集大全:https://www.cnblogs.com/longjee/p/8675771.html

在这里插入图片描述

将3(int)值入栈

在这里插入图片描述

将操作数栈顶的值保存到局部变量表下标为0的局部变量中

在这里插入图片描述

从局部变量表下标为0的局部变量中取值并压入栈中

在这里插入图片描述

将栈顶两个int类型数相加,结果入栈

在这里插入图片描述

返回int类型值

在这里插入图片描述

7.3.1、栈帧

在这里插入图片描述

局部变量obj声明在局部变量表中,但是实际对象的示例创建在了堆中,所以局部变量表中的对象指向堆。

在这里插入图片描述

静态变量在类装载的准备阶段时赋予内存空间并且初始化默认值null,在初始化阶段时在堆中创建实例对象,并且方法区里面的obj指向堆中的实例对象。

在这里插入图片描述

java对象内存布局:其中Class Pointer会从堆指向方法区去获取类的元数据(证明可以从堆指向方法区),同时能够大概算出一个方法占用多大的内存空间(对齐填充保证对象的大小为8字节的整数倍)

在这里插入图片描述

在这里插入图片描述

7.4、本地方法栈

因为调用的是C语言,所以不做过多探讨。

7.5、程序计数器

记录CPU轮转前执行到的地址,以便CPU下次继续调用。

8、内存模型

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

9、垃圾回收机制

9.1、确定什么样的对象是垃圾?

引用计数(会有问题,循环引用的问题)

可达性分析(GC Root,由它出发,某个对象Person对象是否可达)

在这里插入图片描述

9.2、该如何回收?

回收算法

1)标记-清除算法

问题:

a:空间碎片。

b:标记和清除要分别扫描一遍堆,比较耗时,效率较低。

2)复制算法

第一步也是标记。

第二步并不是回收,而是将存活的对象复制到保留区,并且保证保留区空间连续。

第三步清空原数据区,作为新保留区。

弊端:空间浪费,需要浪费一半的空间作为保留区,用于复制保留存活的对象。

优势:空间连续。

3)标记-整理算法

第一步同样是标记。

第二步将存活的对象往一边移动。

第三步清空边界外的内存。

9.3、垃圾收集器

在这里插入图片描述

在这里插入图片描述

9.3.1、只需了解的垃圾收集器

Serial垃圾收集:适用于新生代,使用复制算法,单线程模式

ParNew垃圾收集器:适用于新生代,复制算法,多线程

ParallelScavenge垃圾收集器:使用于新生代,复制算法,多线程,关注吞吐量

SerialOld:老年代,标记-整理算法,单线程

ParallelOld:老年代,标记-整理算法,多线程,关注吞吐量

在这里插入图片描述

多线程类型垃圾收集器示例图:

在这里插入图片描述

9.3.2、CMS垃圾收集器

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

注:压缩算法的意思应该是把存活对象往一边移动的算法,如标记-整理算法。

在这里插入图片描述

并发模式失败的情况:

1、并发清理的时候,还有应用程序线程在申请新的空间以及产生浮动垃圾,此时CMS并不能处理这些浮动垃圾,此时如果CMS执行时预留的空间不够应用程序申请的空间的话,就会出发并发模式失败,导致另一次Full GC,启用后备收集器Serial Old释放可用空间,消除空间碎片,但是会产生全局停顿,停止所有的java应用线程,并且执行相当长的时间。

2、老年代空间碎片化到达一定程度,导致无法在申请新的连续空间存放相应对象的时候,触发并发模式失败。

在这里插入图片描述

在这里插入图片描述

注:压缩算法的意思应该是把存活对象往一边移动的算法,如标记-整理算法。

9.3.3、G1垃圾收集器

停顿时间可调控,但是不能太严格,调的太小会影响垃圾回收,最后导致OOM。

在这里插入图片描述

Region 区域 对堆重新进行了布局,逻辑上存在Yound,Old,Eden,物理上已经不是隔离的了。

在这里插入图片描述

9.4、优势和劣势,该如何进行选型?

​ 优先让JVM自己去选择,如果还没有办法满足的话,可以动态的调整堆的大小,堆空间越大,GC次数越少。

如果还没有办法满足的话,内存空间小于100M或者单线程并且没有太多停顿时间的要求的话,可以选择Serial GC。

如果没有停顿时间的要求,但是想要尽可能的提高吞吐量,可以选择并行的收集器。

如果对停顿时间要求比较高,可以选择并发收集器。

在这里插入图片描述

9.5、学会查看垃圾回收的日志文件?

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值