JVM基础总结01 - 配置参数
〇、JVM体系结构及垃圾回收算法
一、GCRoots
二、JVM的标配参数和X参数
三、JVM的XX参数
1.布尔类型
2.KV设值类型
3.查看参数设置
4.XmsXmx
四、参数修改
五、常用基础参数
1.示例
2.PrintGCDetails回收前后对比
3.SurvivorRatio
4.NewRatio
5.MaxTenuringThreshold
〇、JVM体系结构及垃圾回收算法
1.GC作用区域:方法区+堆内存
2.常见的垃圾回收算法:
- 引用计数法
- 复制算法
优点:没有内存碎片
缺点:浪费50%内存空间
- 标记清除
效率高,但是会产生大量的内存碎片
- 标记整理
标记后压缩,往一端滑动存活对象。没有内存碎片,但是有移动对象的成本
- 分代收集算法
3.MinorGC过程
一、GCRoots
1.JVM垃圾回收的时候如何确定垃圾?是否知道什么是GC Roots
垃圾:内存中已经不再被使用到的空间被称为垃圾
确定垃圾的方法:
引用计数法,有引用的地方+1,引用失效计数-1。这种方法很难解决对象间的互相引用
根搜索路径法(可达性分析法)
GCRoots 垃圾回收根节点
- 虚拟机栈(栈帧局部变量表)中的引用对象
- 方法区中静态属性引用的对象
- 方法区中常量引用对象
- 本地方法栈(JNI)引用的对象
2.Minor GC发生在Eden区;Young GC发生在Eden、S0、S1区;Major GC发生在Old区
Full GC 就是收集整个堆,包括新生代,老年代,永久代(在JDK 1.8及以后,永久代会被移除,换为metaspace)等收集所有部分的模式
3.jvm-gc什么时候会触发 参考:https://blog.csdn.net/qq_33144919/article/details/102131680
3-1.问:minor gc什么时候被触发?
触发minor gc的关键在于:eden区内存不足。
造成eden区内存不足的原因:由于java对象大部分都是朝生夕死(java局部对象),而死掉的对象就需要在合适的时机被jvm回收
这里就涉及到根搜索算法,java对象的关联关系其实就是一个树形结构,从根到叶子节点遍历,死掉的对象也就和根断开了连接关系,
没有死掉的对象也会由于minor gc被强制断开关系。
3-2.问:minor gc执行过程?
由于minor gc是针对年轻代,年轻代又分eden和suivivor区,
suivivor区又分from和to,在发生minor gc的时候,jvm会对对象进行回收(涉及到eden和suivivor的from),为什么只涉及eden和from?因为此时to是空的。
这里就要牵扯到from和to的转换问题。在GC开始的时候,对象只会存在于Eden区和名为“From”的Survivor区,Survivor区“To”是空的。
紧接着进行GC,Eden区中所有存活的对象都会被复制到“To”,而在“From”区中,仍存活的对象会根据他们的年龄值来决定去向。
年龄达到一定值(年龄阈值,可以通过-XX:MaxTenuringThreshold来设置)的对象会被移动到年老代中,没有达到阈值的对象会被复制到“To”区域。
经过这次GC后,Eden区和From区已经被清空。这个时候,“From”和“To”会交换他们的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。
不管怎样,都会保证名为To的Survivor区域是空的。Minor GC会一直重复这样的过程,直到“To”区被填满,“To”区被填满之后,会将所有对象移动到年老代中。
3-3.问:full gc什么时候被触发?
(1)年老代内存不足;
(2)持久代内存不足;
(3)统计得到的Minor GC晋升到旧生代的平均大小大于旧生代的剩余空间,
这是一个较为复杂的触发情况,Hotspot为了避免由于新生代对象晋升到旧生代导致旧生代空间不足的现象,在进行Minor GC时,做了一个判断,
如果之前统计所得到的Minor GC晋升到旧生代的平均大小大于旧生代的剩余空间,那么就直接触发Full GC。
(4) CMS GC时出现promotion failed和concurrent mode failure
对于采用CMS进行旧生代GC的程序而言,尤其要注意GC日志中是否有promotion failed和concurrent mode failure两种状况,当这两种状况出现时可能会触发Full GC。
promotion failed是在进行Minor GC时,survivor space放不下、对象只能放入旧生代,而此时旧生代也放不下造成的;
concurrent mode failure是在执行CMS GC的过程中同时有对象要放入旧生代,而此时旧生代空间不足造成的。
应对措施为:增大survivor space、旧生代空间或调低触发并发GC的比率,但在JDK 5.0+、6.0+的版本中有可能会由于JDK的bug29导致CMS在remark完毕后很久才触发sweeping动作。
对于这种状况,可通过设置-XX: CMSMaxAbortablePrecleanTime=5(单位为ms)来避免。
(5)调用System.gc的时候,虽然这个过程不可控。
二、JVM的标配参数和X参数
1.JVM参数类型
- 标配参数:-version -help java -showversion
- X参数
-Xint:解释执行
-Xcomp:第一次使用就编译成本地代码
-Xmixed:混合模式
- XX参数
三、JVM的XX参数
1.布尔类型
公式:-XX:+或者- 某个属性,+表示开启、-表示关闭
示例:是否打印GC收集细节 -XX:-PrintGCDetails、-XX:+PrintGCDetails
public class HelloGC {
public static void main(String[] args) throws Exception {
System.out.println("Hello GC");
Thread.sleep(Integer.MAX_VALUE);
}
}
VM options: -XX:+PrintGCDetails
验证:
1.jps -l列出当前java进程
2.jinfo -flag PrintGCDetails 进程号 就可以查看是否开启打印GC日志
2.KV设值类型
公式:-XX:属性key=属性值value
示例:-XX:MetaspaceSize=128m、-XX:MaxTenuringThreshold=15
3.查看参数设置
jinfo举例,如何查看当前运行程序的配置
公式:jinfo -flag 配置项 进程进程号、jinfo -flags 进程号(查询所有设置参数)
4.Xms Xmx属于XX参数类型
-Xms 等价于 -XX:InitalHeapSize
-Xmx 等价于 -XX:MaxHeapSize
四、参数修改
调参实际是调XX参数
1.查看JVM初始默认参数
java -XX:PrintFlagsInitial
2.查看修改更新
java -XX:+PrintFlagsFinal
= 没被修改过
:= JVM默认加载时修改过或人为修改过
3.示例PrintFlagsFinal举例,运行Java命令的同时打印出参数
java -XX:PrintFlagsFinal -Xss 128k T(运行Java类的名字)
4.-XX:+PrintCommandLineFlags
五、常用基础参数
-Xms 初始大小内存,默认为物理内存1/64 等价于-XX:InitialHeapSize
-Xmx 最大分配内存,默认为物理内存1/4 等价于-XX:MaxHeapSize
-Xss 设置单个线程栈的大小,一般默认为512~1024K;0代表默认出厂值(不同的平台默认值不一样,一般1M,windows依赖于虚拟内存大小) 等价于-XX:ThreadStackSize
-Xmn 设置年轻代大小
-XX:MetaSpaceSize 设置元空间大小 (默认21M)
元空间本质和永久代类似,都是对JVM中方法区的实现。
元空间与永久代之间最大的区别是:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制
-Xms10m -Xmx10m -XX:MetaSpaceSize=1024m -XX:+PrintFlagsFinal
1.示例 -Xms128m -Xmx4096m -Xss1024k -XX:MetaSpaceSize=512m -XX:+PrintCommandLineFlags -XX:+PrintGCDetails -XX:+UseSerialGC
2.PrintGCDetails回收前后对比
GC日志模板解释:
[名称: GC前占用内存大小 -> GC后占用内存大小 (该区内存总大小)]
3.SurvivorRatio
-XX:SurvivorRatio 设置新生代中eden和s0/s1空间的比例,-XX:SurvivorRatio=4, Eden:s0:s1=4:1:1
4.NewRatio
-XX:NewRatio 配置年轻代与老年代在堆结构的占比,NewRatio就是老年代占比-XX:NewRatio=4 新生代:老年代=1:4 注:此时年轻代就占整个堆内存的1/5
5.MaxTenuringThreshold
-XX:MaxTenuringThreshold 设置垃圾最大年龄 设置范围0~15,默认设置=15
(至于为什么是 15次,原因是 HotSpot会在对象头的中的标记字段里记录年龄,分配到的空间只有4位,所以最多只能记录到15)