一、第二课 Java是如何运行起来的
写好的java文件会被编译成class文件,类加载器会将class类加载到JVM中,JVM会基于自己的字节码执行引擎,来执行加载到内存中的那些类
二、第三课 JVM的类加载机制
1、类加载过程
一个类从加载到使用会经历下面的这个过程
加载、验证、准备、解析、初始化、使用、卸载
加载阶段:只有用到什么类,才会加载什么类
验证阶段:校验加载进来的class文件是否符合规范
准备阶段:给加载进来的类分配内存空间、类变量(static修饰的)分配内存空间、赋予初始值
准备阶段给类变量赋值,只会赋予初始值,例如private static int number = 10,那么number的值是0。除非是private static final int number = 10这样的常量,才会直接赋予10
初始化阶段:执行初始化代码,包括给静态变量赋值,执行静态代码块方法
2、类加载器和双亲委派机制
类加载主要分为:启动类加载器(Bootstrap ClassLoader)、扩展类加载器(Extension ClassLoader)、应用程序类加载器(Application ClassLoader)、自定义加载器
3、思考题
问题:如何保证class文件不会被被人反编译
回答:编译时对class文件加密,在类加载时,自定义类加载器实现解密
三、JVM的内存区域
1、第四课 各内存区域讲解
方法区(jdk8前由永久代实现,jdk8后由元数据区实现):存放类信息(Kafka.class),jdk8之前方法区也存放静态变量
程序计数器:用来记录当前执行到哪一条字节码指令
虚拟机栈:每个线程会创建一个虚拟机栈
本地方法栈:每个线程会创建一个本地方法栈
栈帧:一个线程执行一个方法,就会在虚拟机栈中创建一个栈帧,栈帧内有局部变量表、操作数栈、动态链接、方法出口等
堆内存:存放创建的各种对象,对象的成员变量。jdk8之后也存放静态变量。栈帧的局部变量表只存放堆中对象的地址
堆外内存:不归JVM管的内存 ,例如NIO中的allocateDirect就可以在堆外分配内存,然后通过DirectByteBuffer来操作堆外内存
JDK8以前内存模型:
JDK8后内存模型:
元数据区并不在虚拟机中,而是使用本地内存
2、总结
JVM支持多个线程,所以写好的代码可能有多个线程并发执行不同的代码指令,因此每个线程会有一个自己的程序计数器,专门记录当前线程执行到哪一条字节码指令了。线程在执行方法时,为每个方法都得创建一个栈帧放入自己的Java虚拟机栈中去,里面有方法的局部变量
3、思考题
问题:Tomcat这种Web容器中的类加载器应该如何设计实现?
回答:
Tomcat类加载流程图
四、第五课 JVM垃圾回收机制
如果某个实例对象没有任何一个方法的局部变量指向它,也没有任何一个类的静态变量,包括常量等指向它,那么垃圾回收线程就会把这个实例对象回收掉,从内存里清除掉