1、 JVM体系结构概述
1.1 JVM系统架构图
这张图必须会画出来!!!
1.2 JVM位置
1.3 类加载器ClassLoader
负责加载class文件,class文件在文件开头有特定的文件标示,将class文件字节码内容加载到内存中,并将这些内容转换成方法区中的运行时数据结构并且ClassLoader只负责class文件的加载,至于它是否可以运行,则有Execution Engine决定。
(1)虚拟机自带的加载器
- 启动类加载器(Bootstrap)C++
- 拓展类加载器(Extension)Java
- 应用程序类加载器(AppClassLoader)java也叫系统类加载器,加载当前应用的classpath的所有类
(2)用户自定义加载器:java.lang.ClassLoader的子类,用户可以定制类的加载方式
1.4 双亲委派、沙箱安全机制
当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成,每一个层次类加载器都是如此,因此所有的加载请求都应该传送给启动类加载器中,只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的Class),子类加载器才会尝试自己去加载。
采用双亲委派的一个好处是比如加载位于rt.jar包中的类java.lang.Object,不管是哪个加载器加载这个类,最终都是委拖给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载器最终的到的都是同一个Object对象。
1.5 Native Interface本地接口
1.6 Native Method Stack
1.7 程序计数器(Program Counter Register)
每个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码(用来存储指向下一条指令的地址,也即将要执行的指令代码),由执行引擎读取下一条指令,是一个非常小的内存空间,几乎可以忽略不记。
这块内存区域很小,它是当前线程所执行的字节码的行号指示器,字节码解释器通过改变这个计数器的值来选取下一条需要执行的字节码指令。
如果执行的是一个Native方法,那这个计数器是空的。
用以完成分支、循环、跳转、异常处理、线程恢复等基础功能。不会发生内存溢出(OutOfMemory=OOM)错误
1.8 方法区(Method Area)
供各线程共享的运行时内存区域。它存储了每一个类的结构信息,例如运行时常量池(Runtime constant Pool)、字段和方法数据、构造函数和普通方法的字节码内容。上面讲的是规范,在不同的虚拟机里头实现是不一样的,最典型的就是永久代(PermGen space)和元空间(Metaspace)。But,实例变量存在堆内存中和方法区无关。
1.9 java栈(Java stack)
程序 = 算法 + 数据结构
程序 = 框架 + 业务逻辑
栈管运行,堆管存储
栈保存那些东东?
8种基本类型的变量+对象的引用变量+实例方法都是在函数的栈内存中分配
定义:
栈也叫栈内存,主管java程序的运行,是在线程创建时创建,它的生命期是跟随线程的生命期,线程结束栈内存也就释放,对于栈来说不存在垃圾回收问题,只要线程一结束该栈就Over,生命周期和线程一致,是线程私有的。8种基本类型的变量+对象的引用变量+实例方法都是在函数的栈内存中分配
栈存储什么?
栈帧中主要保存3类数据:
本地变量(Local Variables):输入参数和输出参数及方法内的变量
栈操作(Operand Stack):记录出栈、入栈的操作
栈帧数据(Frame Data):包括类文件、方法等等
栈运行原理
java.lang.StackOverflowError
这是一个ERROR
栈+堆+方法区的交互关系
2、堆(Heap)体系结构概述
栈管运行,堆管存储
- 新生区NEW
- 伊甸区(Eden Space)
Eden满了,开启GC
GC = YGC
Eden基本全部清空 - 幸存0区(Survivor 0 Space)
S0 = from
S1 = to
交换???
from区和to区,他们的位置和名分,不是固定的,每次GC后会交换GC之后有交换,谁空谁是to。 - 幸存1区(Survivor 1 Space)
- 伊甸区(Eden Space)
- 养老区OLD
OLD养老区满了,开启
Full GC = FGC
FULL GC多次,发现养老区空间没办法腾出来,报内存异常OOM。 - 元空间
堆的生命周期
3、堆参数调优入门
JVM垃圾回收
gc算法总体概述
GC是什么(分代收集算法)
次数上频繁收集Young区
次数上较少收集Old区
基本不动元空间
4算法
1、引用计数法
2、复制算法(Copying)
缺点:
3、标记清除(Mark-Sweep)
老年代一般是由标记清除或标记清除和标记整理的混合实现。
4、标记压缩(Mark-Compact)
小总结
哪个算法最好?
无,没有最好的算法,只有最合适的算法,分代收集算法,
面试题
1、JVM内存模型以及分区,需要详细到每个区放什么
2、堆里面的分区:Eden,survival from to,老年代,各自的特点。
3、GC的三种收集方法:标记清除、标记整理、复制算法的原理与特点,
4、Minor GC与Full GC分别在什么时候发生?
JMM(java内存模型)
1、volatile是java虚拟机提供的轻量级的同步机制
- 保证可见性
- 不保证原子性
2、JMM你谈谈
- 可加性
- 原子性
- 有序性
- volatileDemo代码演示可见性+原子性代码
/**
* 定义资源类,变量会在主存中
*/
class MyNumber{
volatile int number = 10;
public void numberTo20(){
this.number = 20;
}
}
public class JMMDemo {
public static void main(String[] args) {
MyNumber myNumber = new MyNumber();
//AAA线程在自己的工作区修改自己线程中变量number的值,并写入主存
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"******come in******");
myNumber.numberTo20();
System.out.println(myNumber.number);},"AAA").start();
// 主线程判断
while (myNumber.number == 10){
}
System.out.println("******end******");
}
}
3、你在哪些地方用到过volatile?
代码加载顺序
class CodeZY{//加载顺序 静态块(只加载一次)>构造块>构造方法
public CodeZY(){
System.out.println("code的构造方法111");
}
{
System.out.println("code的构造块222");
}
static {
System.out.println("code的静态代码块333");
}
}
public class CodeBlock03 {//主类 codeBlocks03.class->main
{
System.out.println("CodeBlock03的构造块444");
}
static {
System.out.println("CodeBlock03的静态代码块555");
}
public CodeBlock03(){
System.out.println("CodeBlock03的构造方法666");
}
public static void main(String[] args) {
System.out.println("***CodeBlock03的main方法777***");
new CodeZY();
System.out.println("--------------------");
new CodeZY();
System.out.println("--------------------");
new CodeBlock03();
}
}