GC调优步骤:
1、打印GC日志
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -Xloggc:./gc.log
Tomcat则直接加在JAVA_OPTS变量里
2、分析日志得到关键性指标
3、分析GC原因,调优JVM参数
jdk:java命令+jre
jvm
栈内存解析
一个方法一个栈帧 栈-先进后出 方法结束后销毁
局部变量表,操作数栈
javap命令
程序计数器:
操作数栈:程序在运行过程中,放操作数的临时空间
方法出口
本地方法:java的native修饰的方法,底层c语言,95年java出现,调用 c语言有xx.dll(类似java的jar包)
本地方法栈:java程序运行到本地方法,需要内存空间存放,内存空间放在本地方法栈
栈,本地方法栈,程序计数器都是每个线程独有的,堆和方法区是线程共享的
堆
满了后字节码执行引擎进行minor,gc
找gc roots找到其引用的对象,变量,直到找到最后一个对象不在引用其他对象,都标记为非垃圾对象,直接复制到Survivor区(复制算法),把没有指针指向的全部销毁掉
垃圾回收机制
对象
gc加1 结合来的博客理解
java的jvisualvm --jdk自带工具,识别所有的jvm进程
测试代码
分代年龄达到15g,直接挪到老年代
old满了,jvm底层满了,会做full gc(后台开启的线程),对这整个区进行垃圾回收;
老年代的full gc无法回收就OOM
JVM调优-STW(stop the word)
gc回收,用户线程暂停,用户会感到停顿;如果不暂停用户线程,在gc root执行期间,找到的都是非垃圾线程,用户线程执行突然执行完毕,会导致gc root找到的非垃圾线程没有引用,变为垃圾线程进行回收,所以设置STW
jvm调优目的
full gc--用户感觉卡
上图13秒的时候,剩余的60M占比s0和s1区超过50%,会放在full gc(老年代),几分钟后,full gc满了,就会OOM
每秒会有60M给eden放,大概13秒会占满eden,放满后会触发minor gc,会回收eden区的垃圾对象(没有被gc root引用的),12s产生的会回收,第13s有可能不回收,触发gc, 会暂停用户的线程,暂停的时候会gc root引用着,第13秒的对象就不是垃圾对象了,直接就会挪到Survivor区
当分代年龄达到15岁,会挪到老年代,大的对象,放不到eden区,也会直接到老年代;
产生的60M对象大于Survivor的一半,会直接放到老年代,再过1s,又会变成垃圾对象,每过13s,做一次minor gc,每做一个minor gc都会有一批60M对象放入Survivor,触发了对象动态年龄判断机制,会挪到老年代,2g的老年代,几分钟就会放满,放满后会触发full gc ;
面试题(阿里):对jvm优化,几乎不发生full gc?
eden:s0:s1=8:1:1
老年代(old)不放2g,放1g ;eden1.6g,大概25s放满
60M小于Survivor(200M)的50%,不会挪到老年代,几乎避免了full gc