目录
一、JMM内存模型
1、定义
2、JMM的三大特性(可见性+原子性+有序性)
2.1 可见性
2.2 原子性
2.3 有序性
3、JMM中的8种原子操作
二、JVM
1、JVM体系结构
2、JVM参数调优
2.1 三大参数类型
2.2 九个调优参数
三、垃圾回收器
1、4种GC算法(引用计数 /复制拷贝/标记清除/标记整理)
2、4种垃圾回收器
2.1 主要4个(Serial / Parallel / CMS / G1)
2.2 其它3个(ParNew / ParallelOld / SerialOld)
3、使用范围
本文通过学习:周阳老师-尚硅谷Java大厂面试题第二季 总结的JMM,JVM,GC垃圾回收相关的笔记
一、JMM内存模型
1、定义
JMM是Java内存模型,也就是Java Memory Model,简称JMM,本身是一种抽象的概念,实际上并不存在,它描述的是一组规则或规范,通过这组规范定义了程序中各个变量(包括实例字段,静态字段和构成数组对象的元素)的访问方式
JMM关于同步的规定:
(1)线程解锁前,必须把共享变量的值刷新回主内存
(2)线程解锁前,必须读取主内存的最新值,到自己的工作内存
(3)加锁和解锁是同一把锁
|
主内存 | 计算机的内存,也就是经常提到的8G内存,16G内存 |
工作内存 | 实例化 new student,那么 age = 25 也是存储在主内存中。当同时有三个线程同时访问 student中的age变量时,那么每个线程都会拷贝一份,到各自的工作内存,从而实现了变量的拷贝 |
2、JMM的三大特性(可见性+原子性+有序性)
2.1 可见性
当主内存区域中的值被某个线程写入更改后,其它线程会马上知晓更改后的值,并重新得到更改后的值。
2.2 原子性
一个或多个操作,要么全部执行,要么全部不执行。
2.3 有序性
(1)有序性:在本线程内观察,所有的操作都是有序的;而在一个线程内观察另一个线程,所有操作都是无序的。前半句指 as-if-serial 语义:线程内似表现为串行,后半句是指:“指令重排序现象”和“工作内存与主内存同步延迟现象”。处理器为了提高程序的运行效率,提高并行效率,可能会对代码进行优化。编译器认为,重排序后的代码执行效率更优。这样一来,代码的执行顺序就未必是编写代码时候的顺序了,在多线程的情况下就可能会出错。
(2)有序性问题:在多线程的环境下,由于执行语句重排序后,重排序的这一部分没有一起执行完,就切换到了其它线程,导致计算结果与预期不符的问题。这就是编译器的编译优化给并发编程带来的程序有序性问题。
3、JMM中的8种原子操作
(1)read 读取:作用于主内存,将共享变量从主内存传送到线程的工作内存中。
(2)load 载入:作用于工作内存,把 read 读取的值放到工作内存中的副本变量中。
(3)store 存储:作用于工作内存,把工作内存中的变量传送到主内存中。
(4)write 写入:作用于主内存,把从工作内存中 store 传送过来的值写到主内存的变量中。
(5)use 使用:作用于工作内存,把工作内存的值传递给执行引擎,当虚拟机遇到一个需要使用这个变量的指令时,就会执行这个动作。
(6)assign 赋值:作用于工作内存,把执行引擎获取到的值赋值给工作内存中的变量,当虚拟机栈遇到给变量赋值的指令时,就执行此操作。
(7)lock锁定: 作用于主内存,把变量标记为线程独占状态。
(8)unlock解锁: 作用于主内存,它将释放独占状态。
二、JVM
1、JVM体系结构
2、JVM参数调优
查看JVM默认参数的三种方法
方法1 | jps + jinfo | jps -l 查看java进程 jinfo flag 参数名 进程ID 查看某JVM参数 jinfo flags 进程ID 查看所有JVM参数 |
方法2 | java -XX:+PrintFlagsInitial java -XX:+printFlagsFinal | PrintFlagsInitial 打印JVM初始参数 =表示未修改过, :=表示已修改过 |
方法3 | java -XX:+PrintCommandLineFlags | 打印JVM默认的简单初始化参数 |
2.1 三大参数类型
参数类别 | 说明 | 示例 |
标配参数 |
| java -version java -help |
X参数(掌握) |
| java -Xint -version java -Xcomp -version java -Xmixed -version |
XX参数(重点) |
| java -XX:-PrintGCDetails 关闭了GC详情输出 java -XX:MetaspaceSize=21807104 查看Java元空间的值 |
问:如何查看JVM系统默认值?
答:一般使用jps和jinfo进行查看。jps查看java的后台进程,jinfo查看正在运行的java程序,
jinfo -flags *** 查看jvm的全部默认参数。jinfo -flag PrintGCDetails 进程ID 查看某个参数。
//运行一个HelloGC的java程序 public class HelloGC { public static void main(String[] args) throws InterruptedException { System.out.println("hello GC"); Thread.sleep(Integer.MAX_VALUE); } } | jps -l 查看到HelloGC的进程号为:12608 jinfo -flag PrintGCDetails 12608 jinfo -flag 然后查看是否开启PrintGCDetails这个参数 -号表示关闭,即没有开启PrintGCDetails这个参数 |
问:如何开启PrintGCDetails参数?
答:step1、IDEA的 Run ---> Edit Configurations
然后,在VM Options中加入下面的代码,现在+号表示开启
-XX:+PrintGCDetails
step2、再次查看
jps -l
jinfo -flag PrintGCDetails 13540
得到:-XX:+PrintGCDetails,说明通过VM Options配置的JVM参数已经生效了。
2.2 九个调优参数
6个常用调优参数
-Xms | 初始化堆内存 | 默认为物理内存的1/64,等价于 -XX:initialHeapSize java -xms 10m |
-Xmx | 最大堆内存 | 默认为物理内存的1/4,等价于 -XX:MaxHeapSize java -xmx 10m |
-Xss | 单个线程栈的大小 | 默认为512K~1024K,等价于 -XX:ThreadStackSize |
-Xmn | 设置年轻代大小 | |
-XX:MetaspaceSize | 设置元空间大小 |
|
-XX:PrintGCDetails | 输出详细GC收集日志信息 |
|
3个垃圾回收相关的调优参数
-XX:SurvivorRatio | 调节新生代中 eden 和 S0、S1的空间比例 | java -XX:SuriviorRatio=8 表示 Eden:S0:S1 = 8:1:1 |
-XX:NewRatio (了解即可) | 配置年轻代new 和老年代old 在堆结构的占比 | java -XX:NewRatio=2 新生代占1,老年代2,年轻代占整个堆的1/3 |
-XX:MaxTenuringThreshold | 设置垃圾最大年龄 | java -XX:MaxTenuringThreshold=15 SurvivorTo和SurvivorFrom互换,原SurvivorTo成为下一次GC时的SurvivorFrom区,部分对象会在From和To区域中复制来复制去,如此交换15次(由JVM参数MaxTenuringThreshold决定,这个参数默认为15),最终如果还是存活,就存入老年代 这里就是调整这个次数的,默认是15,并且设置的值 在 0~15之间。
|
GC垃圾收集器
GC | GC在新生区 |
Full GC | Full GC大部分发生在养老区 [名称: GC前内存占用 -> GC后内存占用 (该区内存总大小)] 当出现了老年代都扛不住的时候,就会出现OOM异常 |
三、垃圾回收器
GC算法和垃圾回收器的区别:GC算法是内存回收的方法论,垃圾收集器就是算法的落地实现
1、4种GC算法(引用计数 /复制拷贝/标记清除/标记整理)
- 引用计数(几乎不用,无法解决循环引用的问题)
- 复制拷贝(用于新生代)
- 标记清除(用于老年代)
- 标记整理(用于老年代)
2、4种垃圾回收器
2.1 主要4个(Serial / Parallel / CMS / G1)
UseSerialGC: 串行垃圾收集器 | UseParallelGC: 并行垃圾收集器 | UseConcMarkSweepGC: 并发标记清除(即CMS) | UseG1GC: G1垃圾收集器 |
它为单线程环境设计且值使用一个线程进行垃圾收集,会暂停所有的用户线程,只有当垃圾回收完成时,才会重新唤醒主线程继续执行。所以不适合服务器环境 | 多个垃圾收集线程并行工作,此时用户线程也是阻塞的,适用于科学计算 / 大数据处理等弱交互场景,也就是说Serial 和 Parallel其实是类似的,不过是多了几个线程进行垃圾收集,但是主线程都会被暂停,但是并行垃圾收集器处理时间,肯定比串行的垃圾收集器要更短 | 用户线程和垃圾收集线程同时执行(不一定是并行,可能是交替执行),不需要停顿用户线程,互联网公司都在使用,适用于响应时间有要求的场景。并发是可以有交互的,也就是说可以一边进行收集,一边执行应用程序。 | 将堆内存分割成不同区域,然后并发的进行垃圾回收 |
2.2 其它3个(ParNew / ParallelOld / SerialOld)
UseParNewGC 年轻代的并行垃圾回收器 | UseSerialOldGC 串行老年代垃圾收集器 (已经被移除) | UseParallelOldGC 老年代的并行垃圾回收器 |
3、使用范围
新生代 | UserSerialGC、UserParallelGC、UserParNewGC |
老年区 | UseConcMarkSweepGC、UseSerialOldGC、UseParallelOldGC |
各区都能用 | UseG1GC |