1.JVM来及回收的时候如何确定垃圾以及谈谈你对GCRoots的理解
引用计数法
和可达性分析
来判断一个对象是不是垃圾- GC Roots用来做垃圾回收时的可达性分析的
- 可以用作GC Roots对象:
- 虚拟机栈(栈帧中的局部变量区,也叫做局部变量表)中引用的对象。
- 方法区中的类静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈中JNI(Native方法)引用的对象
2. JVM调优和参数配置
新生代:1/3堆空间【Eden(8/10),From(1/10),To(1/10)】
老年代:2/3堆空间
jps -l # 查看正在运行的java程序
jinfo -flag PrintGCDetails 进程号 # 有没有开启PrintGCDetails
jinfo -flags 进程号 # 查看所有的参数信息
java -XX:+PrintFlagsInitial # 查看参数盘点家底
java -XX:+PrintFlagsFlagsFinal -version # 查看修改更新,:=表示修改更新过的值
java -XX:+PrintCommandLineFlags -version # 查看参数信息
XX参数设置:
boolean 类型
:-XX:+或者-某个属性值- 例如:-XX:+PrintGCDetails
KV设值类型
:-XX:属性key=属性值value- 例如:-XX:MetaspaceSize=1024m
-Xms
等价于-XX:InitialHeapSize
初始化堆内存,默认为物理内存的1/64-Xmx
等价于-XX:MaxHeapSize
最大堆内存,默认为物理内存的1/4-Xss
等价于-XX:ThreadStackSize
设置单个线程栈的大小,默认为512k~1024k-Xmn
设置年轻代大小,一般这个参数都用默认的,不调整-XX:MetaspaceSize
设置元空间大小-XX:SurvivorRatio
设置新生代的新生代区比例,默认是8:1:1-XX:NewRatio
设置新生代和老年代的比例,默认是1:2-XX:MaxTenuringThreshold
设置垃圾最大年龄
3. 谈谈OOM
- StackOverflowError:栈溢出异常
- Java heap space:堆内存不足
- GC overhead limit exceeded:GC回收时间过长
- Direct buffer memory:直接内存不足
- unable to create new native thread:不能再创建新线程了
- Metaspace:元空间溢出
4. 垃圾收集器
Serial
:为单线程环境设计且只使用一个线程进行垃圾回收,会暂停所有的用户线程。Parallel
:多个垃圾收集线程并行工作,此时用户线程是暂停的,适用于科学计算/大数据处理首台处理等弱交互场景。CMS
:用户线程和垃圾收集线程同时执行(不一定是并行,可能交替执行),不需要停顿用户线程互联网公司多用它,适用对响应时间有要求的场景。G1
:将堆内存分割成不同的区域然后并发的对其进行垃圾回收。
垃圾收集器:
- 新生代:
Serila
:串行GC
Parallel/Parallel Scavenge
:并行GC(默认的)
ParNew
:并行GC(为了和CMS联用) - 老年代:
Serial Old
:老年代串行GC
UseConcMarkSweepGC
:并发标记GC
UseParallelOldGC
:老年代并行GC - 新生代老年代:
UseG1GC
:G1
使用细节:
Serial收集器【Serial Old收集器】:
-XX:+UseSerialGC
,开启后会使用Serial(Young区用)+Serial Old(Old区用)的收集器组合
表示:新生代、老年代都会使用串行回收收集器,新生代使用复制算法,老年代使用标记-整理算法
ParNew收集器:
-XX:+UseParNewGC
,只影响新生代,不影响老年代。开启后会使用ParNew(Young区用)+Serial Old(Old区用)的收集器组合
表示:新生代用并行回收,老年代用串行回收,新生代使用复制算法,老年代使用标记-整理算法
Parallel收集器【Parallel Old收集器】:
-XX:+UserParallelGC
,新生代和老年代都用并行收集器,新生代用Parallel,老年代用Parallel Old。
表示:新生代用复制算法,老年代使用标记-整理算法
自适应调节策略
是Parallel收集器和ParNew收集器的一个重要区别。(自适应策略:虚拟机会根据当前系统的运行情况收集性能监控信息,动态调整这些参数以提供最合适的停顿时间或最大的吞吐量)
CMS收集器:
- 一种并发标记清除收集器。
-XX:UseConcMarkSweepGC
,开启该参数后会自动将-XX:UseParNewGC
打开。开启该参数后,使用ParNew(Young区用)+CMS(Old区用)+Serial Old的收集器组合,Serial Old将作为CMS出错的后备收集器。
表示: 新生代用复制算法,老年代用标记-清除算法
G1收集器:
过程:
- 初始标记(CMS initial mark)
只是标记一下GC Roots能够直接关联的对象,速度很快,仍然需要暂停所有的工作线程。
- 并发标记(CMS concurrent mark)
进行GC Roots跟踪过程,和用户线程一起工作,不需要暂停工作线程。主要标记过程,标记全部对象。
- 重新标记(CMS remark)
为了修正并发标记期间,因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录(例如垃圾被重新引用),仍然需要暂停所有的工作线程。
- 并发清除(CMS concurrent sweep)
清除GC Roots不可达对象,和用户线程一起工作,不需要暂停工作线程,基于标记结果,直接清理对象。
-XX:+UseG1GC
:G1整体上采用标记-整理算法,局部是通过复制算法,不会产生内存碎皮。
特点:
- G1能够充分利用多CPU、多核环境硬件优势,尽量缩短STW。
- G1整体上采用标记-整理算法,
局部是通过复制算法,不会产生内存碎片
。 - 宏观上看G1之中不再区分年轻代和老年代。
把内存划分成多个独立的子区域(Region)
,可以近似理解为一个围棋的棋盘。 - G1收集器里面讲整个的内存区都混合在一起了,
但其本身依然在小范围内要进行年轻代和老年代的区分
,保留了新生代和老年代,但它们不再是物理隔离的,而是一部分Region的集合且不需要Region是连续的,也就是说依然会采用不同的GC方式来处理不同的区域。 - G1虽然也是分代收集器,但整个内存分区
不存在物理上
的年轻代与老年代的区别,也不需要完全独立的survivor(to space)堆做复制准备。G1只有逻辑上的分代概念
或者说每个分区都可能随G1的运行在不同代之间前后切换。