GC如何确定垃圾:引用计数法(循环依赖)、可达性分析-从GC Roots开始向下搜索
垃圾回收算法:
标记清除:内存碎片化严重
复制算法:内存分为大小相同的两半,活跃的拷贝的另一半,其余清除掉,浪费空间
标记压缩算法:标记垃圾区域-》移动存活对象-》存活对象以外的区域清除
线程共享:
方法区:常量、静态变量(永久代)
堆:创建的对象和数组
新生代(Eden、serviceorFrom、servicorTo):复制算法(复制-清空-互换)
老年代(标记清除(老年代满后出发fullgc,可能会使用压缩、整理))
线程私有:
程序计数器
虚拟机栈
本地方法区
jvm类加载机制:
启动类加载器-Bootstrap ClassLoader:根加载器,负责加载jvm技术核心类库,%{JDK_HOME}\lib下的rt.jar、resources.jar等
扩展类加载器-Extendion ClassLoader:主要负责%{JDK_HOME}\lib\ext目录下的jar包和class文件
应用类加载器-Application ClassLoader:主要负责当前应用里面的classpath下的所有jar包和类文件
双亲委派机制:向上委派,父类能加载,交给父类加载,父类加载不了,再自己加载
jvm性能调优参数:
设置堆内存大小:-Xmx:堆内存最大限制
设置新生代大小,新生代不宜太小,否则会有大量对象涌入老年代
-XX:NewSize 新生代大小
-XX:NewRatio 新生代和老年代的比例(=老年代/新生代)
-XX:SurvivorRatio 伊甸园区和幸存者空间占比(=eden/from=eden/to,默认eden:feom:to=8:1:1)
设定垃圾回收器,年轻代用 -XX:+UseParNewGC 老年代用-XX:+UseConcMarkSweepGC
查看GC情况:jstat -gc pid
堆栈跟踪:jstack [option] pid(打印给定进程的堆栈信息)
排查和解决JVM OOM:排查思路 问题发现-问题止血-问题分析-问题规避
问题发现:
1、日志监控,通过监控日志搜索关键字java.lang.OutOfMemoryError
2、配置-XX:+ExitOnOutOfMemoryError,当jvm启用该参数时,如果出现了OOM,就会自动退出程序
3、使用jstat监控jvm内存使用率,如果老年代使用率(列明为:O)一直是100,并还在不断GC,则表示发生了OOM,
命令:jstat -gcutil pid 1000 (每秒打印一次该pid的内存使用率情况)
问题止血:
当应用发生OOM时,无法申请到内存分配对象,业务代码就处于混乱状态,不清楚进行到了哪一步,可配置-XX:+HeapDumpOnOutOfMemoryError参数,当发生OOM后,自动关机服务,服务心跳检测异常后发送告警。
问题分析:
分析heap dump文件
问题规避:
OOM发生有两种原因:
1、堆内存设置过小,无法支持正常对象分配;
现象:内存分布正常,没有一下占内存30%-50%的对象
解决方案:增大堆内存;优化应用内存使用率;
2、应用发生了内存泄漏,导致对象没有被清理;
现象:某一类型对象占据了大量的内存空间
可能原因:ThreadLocal未清理(本项目问题ThreadLocal没有remove,只是设置为null);存在未分页的大数据量查询;定时任务集合未清空,一直追加数据。