【0301】 学32Java 面试必考点 + 自己补充、整理

一、JVM 知识汇总

【0301】 学32Java 面试必考点 + 自己补充、整理

二、JVM 内存模型
1、内存模型:程序计数器、方法区、堆、栈、本地方法栈的作用,保存哪些数据?
【0301】 学32Java 面试必考点 + 自己补充、整理

2、栈:方法栈,是线程私有的,线程在执行每个方法时都会同时创建一个栈帧,用来存储局部变量表、操作栈、动态链接、方法出口等信息。调用方法时执行入栈,方法返回时执行出栈。

3、本地方法栈:是用来保存线程执行方法时的信息,不同的是,执行 Java 方法使用栈,而执行 native 方法使用本地方法栈。

4、程序计数器保存着当前线程所执行的字节码位置,每个线程工作时都有一个独立的计数器。程序计数器为执行Java方法服务,执行 native 方法时,程序计数器为空。

栈、本地方法栈、程序计数器这三个部分都是线程独占的

5、堆是 JVM 管理的内存中最大的一块,堆被所有线程共享,目的是为了存放对象实例,几乎所有的对象实例都在这里分配。当堆内存没有可用的空间时,会抛出 OOM 异常。根据对象存活的周期不同,JVM 把堆内存进行分代管理,由垃圾回收器来进行对象的回收管理。

6、方法区是各个线程共享的内存区域,又叫非堆区。用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据,JDK 1.7 中的永久代和 JDK 1.8 中的 Metaspace 都是方法区的一种实现。

三、JMM 与内存可见性

【0301】 学32Java 面试必考点 + 自己补充、整理

1、JMM 主要目标是定义程序中变量的访问规则,提供原子性、可见性、有序性的保证

A:所有的共享变量都存储在主内存*享。每个线程有自己的工作内存,工作内存中保存的是主内存中变量的副本,线程对变量的读写等操作必须在自己的工作内存中进行,而不能直接读写主内存中的变量。

B:在多线程进行数据交互时,线程 A 给一个共享变量赋值后,由线程 B 来读取这个值,A 修改完变量是修改在自己的工作区内存中,B 是不可见的,只有从 A 的工作区写回主内存,B 再从主内存读取自己的工作区才能进行进一步的操作。

C:由于指令重排序的存在,这个写—读的顺序有可能被打乱。

2、JMM 如何保证原子性、可见性,有序性。
【0301】 学32Java 面试必考点 + 自己补充、整理

A: 原子性
JMM 保证对除 long 和 double 外的基础数据类型的读写操作是原子性的。关键字 synchronized 也可以提供原子性保证。synchronized 的原子性是通过 Java 的两个高级的字节码指令 monitorenter 和 monitorexit 来保证的。

B:可见性
JMM可见性的保证, synchronized 、volatile。volatile 强制变量的赋值会同步刷新回主内存,强制变量的读取会从主内存重新加载,保证不同的线程总是能够看到该变量的最新值。

C:有序性
对有序性的保证,主要通过 volatile 和一系列 happens-before 原则。volatile 的另一个作用就是阻止指令重排序,这样就可以保证变量读写的有序性。

3、happens-before 原则包括一系列规则(八条规则),如:

程序顺序原则,即一个线程内必须保证语义串行性;

锁规则,即对同一个锁的解锁一定发生在再次加锁之前;

happens-before 原则的传递性、线程启动、中断、终止规则等。

以前文章
Java内存模型