资源语言: 中文
JVM
基础
类的加载过程
1.java代码
2.打包
maven
jar
war
3.执行
执行class main
引用到其他类通过class字节码一并加入
4.类加载器过程
1.验证
class是否符合JVM规范
比如篡改就无法执行
2.准备
分配空间/默认值
类
静态变量
3.解析
符号引用替换为直接引用
4.初始化
类
先初始化父类
静态变量赋值
静态代码块
类加载器
ClassLoader
1.Bootstrap
启动类
加载lib目录
2.Extension
扩展类
加载llib\ext
3.Application
应用程序
自己写的代码
4.自定义
自定义
可以做一些class加密等
Tomcat热加载也可以在这里做
双亲委派机制
从下游往上查找
作用:为了避免重复加载类
双亲委派机制
JMM 内存模型
方法区
也叫永久代
也叫metaspace元数据空间
存储:加载到jvm的类
程序计数器
执行class字节码 JVM会用到自己的字节码执行引擎
记录当前执行的字节码指令的位置
栈
也叫虚拟机栈
执行方法会创建栈帧压入JVM
作用:保存局部变量表等(操作数栈、动态链接、方法出口)
堆
存储对象数据
局部变量的引用实例
JVM运行过程
类加载到JVM内存
在方法区里面通过JVM字节码引擎执行main方法
同时程序计数器记录并关联了虚拟机栈
虚拟机栈会压入main方法的栈帧
入栈记录局部变量并引用到堆
访问其他方法的时候会创建栈帧压入到JVM
访问结束的时候出栈
JVM分代模型
年轻代
存活周期极短
使用之后立马就可以回收掉的生存周期极短的对象,针对年轻代的垃圾回收我们称为Minor GC也叫做Young GC
老年代
长期存活的
Old GC
永久代
加载的一些jvm类信息
metaspace GC
JVM
JAVA heap space
理论
垃圾的产生
方法入栈,局部变量压入栈帧,同时指向堆内存地址
堆内存存放实例化对象,在方法运行时创建的加载到堆内存
执行方法完毕后,方法出栈,堆内存至此无局部变量引用,变成垃圾。
虚拟机栈执行完部变量消失则产生堆对象无人引用变成垃圾
什么时候回收
内存满了放不下了
没有引用的对象给回收掉
怎么判断没有被引用
可达性分析算法
没有GC Roots一定回收吗
不一定
重写Object finalize赋值
回收类型
强引用
静态变量
不会回收
软引用
SoftReference修饰
一般不回收
除非内存实在不够用了
弱引用
WeakReference修饰
会回收
虚引用
回收算法
可达性分析算法
一层一层往上游判断看是否有一个GC Roots
局部变量就是可以作为GC Roots
静态变量
总结:只要你的对象被方法的局部变量、类的静态变量给引用了,就不会回收他们。
标记清理算法
先通过可达性分析算法追踪GC Roots的方法,看看各个对象是否被GC Roots给引用了,如果是的话,那就是存活对象,否则就是垃圾对象。
先将垃圾对象都标记出来,然后一次性把垃圾对象都回收掉
内存碎片
复制算法
传统复制算法
把内存分为2块
空间利用率低下会产生大量内存碎片
标记可以回收的对象,复制到另外一块区域全部销毁
优化复制算法
分为3块
1个eden和2Survivor
默认比例:8:1:1
通过可达性分析算法标记存活对象,再通过复制算法把eden和一个survivor存活对象放到另外一个Survivor区。然后删除掉eden和survivor 这样不产生内存碎
Stop the World
系统停止处理请求,垃圾回收完再继续处理
假死
GC时候触发
垃圾器
CMS垃圾回收器
标记清理算法
1.老年代存活对象的数量比较大,复制的性能会变得很差
2.标记清理算法会遗留内存碎片
3.必须配合标记整理算法也就是压缩算法把不连续的内存碎片整理为连续空间 可以设置
CMS回收阶段
1,初始标记
理论
方法的局部变量和类的静态变量是GC Roots
类的实例变量不是GC Roots
仅仅标记GC Roots直接引用
特点
STW
效率快
2,并发标记
理论
标记存活对象和垃圾对象
但是并发运行不停创建新对象没被标记
特点
耗时
存活对象多
GC Roots追踪
对老年代所有对象进行GC Roots追踪,其实是最耗时的
并发运行且不会STW不会对系统造成影响
3,重新标记
理论
第二阶段里有很多没标记出来的对象
需要从新标记
还有一些已有对象可能失去引用变成垃圾
特点
STW
4,并发清理
理论
清理掉标记的垃圾对象
特点
耗时
对象多
消耗cpu资源
并发清理不影响系统运行
Concurrent Mode Failure
理论
浮动垃圾
回收期间,系统程序要放入老年代的对象大于了可用内存空间
结果
Serial Old”垃圾回收器替代CMS
STW
重新进行长时间的GC Roots追踪
所以建议设置阈值参数
ParNew垃圾回收器
复制算法
参数
默认并行线程数
-XX:ParallelGCThreads
默认cpu核 4核就是4个线程
不建议调节
指定ParNew
-XX:+UseParNewGC
特点
适用于小堆
如果存活对象的数量比较大,coping的性能会变得很差
原理
Young GC
一旦Eden区塞满之后,就会触发一次Young GC。
Young GC会采用复制算法,从GC Roots(方法的局部变量、类的静态变量)开始追踪,标记出来存活的对象。
然后把存活对象都放入第一个Survivor区域中,也就是S0区域, 接着垃圾回收器就会直接回收掉Eden区和S1里剩余的全部垃圾对象,
G1垃圾回收器
特点
一个垃圾器就可以搞定
设置一个垃圾回收的预期停顿时间
他最大的一个特点,就是把Java堆内存拆分为多个大小相等的Region
理论
Region
回收价值
耗费多长时间
可以回收掉多少垃圾
包含
年轻代
年轻代初始化5%
最大60%
老年代
最大40%
数量内存
JVM最多2048个Region
内存大小必须是2的倍数
动态增加
进入老年代条件
动态规则
年龄
Survivor放不下
大对象
超过了一个Region大小的50%
横跨多个Region来存放
之前不一样新生代、老年代在回收的时候会把大对象Region回收
混合回收
复制算法
和之前区别就是时间设置
尽可能的再预期阈值内回收更多的垃圾
停顿时间
不能设置过大
导致系统运行很久,新生代可能都占用了堆内存的60%了,此时才触发新生代gc
不能设置过小
如果这个参数设置的小了,那么说明每次gc停顿时间可能特别短,此时G1一旦发现你对几十个Region占满了就立即触发新生代gc,然后gc频率特别频繁,虽然每次gc时间很短。
STW
FULL GC/mixed gc
没有空闲Region可以承载自己的存活对象了,就会触发 一次失败
失败则单线程进行标记、清理和压缩整理,空闲出来一批Region和之前cms的cmf是一样的
超过45%就出触发
年轻代和老年代都会进行回收
进入老年代条件
1.存活年龄太大
默认15次
可以设置
2.大对象
3.动态年龄判断规则
超过50%
4.survivor放不下
Minor GC后对象太多无法放入survivor
Full GC的条件
1,超过阈值
2.老年代放不下
3.老年代内存小于历次youngGC平均大小
表现
机器CPU负载过高;
频繁Full GC报警;
系统无法处理请求或者处理过慢
JVM调优
工具
jstat
目标
Young GC的触发频率
新生代对象增长的速率
Young GC的耗时
Young GC后有多少对象是存活
老年代对象增长的速率
Young GC过后有多少对象进入了老年代
Full GC的触发频率
Full GC的耗时
常用命令
jstat -gc PID
知道这些东东就可以合理分配内存
jmap
常用
jmap -histo PID
jmap -dump:live,format=b,file=dump.hprof PID
jhet
jhat dump.hprof -port 7000
MAT
这个比起jhet就强大多了
大对象定位
参数
年轻代
比例
-XX:SurvivorRatio
年龄
XX:MaxTenuringThreshold
大对象
XX:PretenureSizeThreshold
垃圾回收器
UseParNewGC
老年代
整理
-XX:+UseCMSCompactAtFullCollection
默认打开
Stop the World
整理内存碎片
XX:CMSFullGCsBeforeCompaction
多少次GC整理
默认0
阈值
XX:CMSInitiatingOccupancyFaction
默认92%
垃圾回收器
XX:+UseConcMarkSweepGC
空间担保机制
XX:HandlePromotionFailure
并行初始化标记
-XX:+CMSParallelInitialMarkEnabled
重新标记阶段之前YGC
-XX:+CMSScavengeBeforeRemark
G1
新生代初始占比
XX:G1NewSizePercent
默认5%
新生代最大占比
XX:G1MaxNewSizePercent
不超过60%
还是有eden 和survivor理念
-XX:SurvivorRatio
100个Region里面有多少个eden 多少个survivor
混合回收
XX:InitiatingHeapOccupancyPercent
如果老年代占据了堆内存的45%的Region的时候,此时就会尝试触发一个新生代+老年代一起回收的混合回收阶段
默认值是45%
停顿时间
XX:MaxGCPauseMills
默认200ms
回收次数
XX:G1MixedGCCountTarget
默认值是8次
回收干净,让用户无感
闲出来的Region数量
XX:G1HeapWastePercent
默认值是5%
达到了就就会停止回收
存活对象
XX:G1MixedGCLiveThresholdPercent
默认值85%的
一个Region的存活对象多余85%,你还回收他干什么?这个时候要把85%的对象都拷贝到别的Region,这个成本是很高的。
日志
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-Xloggc:gc.log
-XX:TraceClassLoading -XX:TraceClassUnloading
就是追踪类加载和类卸载的情况,他会通过日志打印出来JVM中加载了哪些类,卸载了哪些类。
dump
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/usr/local/app/oom
屏蔽
-XX:+DisableExplicitGC
弱引用
SoftRefLRUPolicyMSPerMB
clock - timestamp <= freespace * SoftRefLRUPolicyMSPerMB
模板
“-Xms4096M -Xmx4096M -Xmn3072M -Xss1M -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFaction=92 -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSParallelInitialMarkEnabled -XX:+CMSScavengeBeforeRemark -XX:+DisableExplicitGC -XX:+PrintGCDetails -Xloggc:gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/app/oom”
OOM
Metaspace
java.lang.OutOfMemoryError:Metaspace
动态生成类cglib
堆
java.lang.OutOfMemoryError:java heap space
高并发请求量过大,导致大量对象存活 内存泄漏,不停的创建对象,被引用
栈
java.lang.StackOverFlowError
一般默认设置每个线程1M
方法调用过多导致压入栈过多内存不够用
遇到过的案例
重试机制
瞬时高并发
try/cach处理
故障
Tomact
Max-http-header-size
重试
jetty
直接内存
Direct buffer memory
survivor设置不合理进入老年代引起的
RPC
A-B B挂
序列化Protobuf不一致
基于Thrift框架自己封装出来的一个RPC框架
序列化失败开辟一个byte[]数组
where
大对象
需要调优
实战
预估内存模型
理论
思路
每个请求的需要耗费多少时间(时间)
每个请求需要多少内存(空间)
每秒钟我们需要处理多少个请求(QPS)
GC
通过上诉就可以估算出
每秒钟生产的垃圾
多久一次youngGC
多久一次OldGC
进入老年代的垃圾
实战
每天上亿请求的电商APP订单系统调优思路
QPS
日活
假设每个用户点击20次请求
500万日活
订单微服务系统
不会每个人都下单所用费用转换率10%
真实日活50万
峰值
APP电商系统场景
一般晚上7点到11点4小时高峰预算
4小时峰值
状态
瞬时高并发
普通高并发
环境
多少台机器部署
算出最终 日活/峰值/机器=每台机器的QPS
内存
订单模型估算比如订单类20个字段
往大了估算*10倍
虚拟机栈局部变量会用掉一些内存
用完就变成垃圾
再往大了估算*20
链路长
修改自己订单状态
推送给第三方服务
短信
仓库
优惠卷
时间
每个请求会执行多久时间
这部分非常用重要
不然会产生大量的对象到达老年代
考虑的问题
通过上诉3大块我们就能估算出合理的GC条件然后进行合理的分配内存
1.多久会触发一次Full GC
2.内存碎片整理的频率应该多高?
3.会发生Concurrent Mode Failure吗?
遇到过的案例
弱引用
system.gc
where大对象
内存泄漏缓存没有LRU
String.split()
OOM
如何解决
日志
那个区域出现异常
栈相关信息
假死
top
cpu
磁盘
内存
网络
原因
内存使用过高
频繁GC STW
过多jvm oom
内存使用过高申请无效被杀
cpu过高回收线程没有资源
分析通过MAT定位大对象
java资源(JVM基础思维导图)网址:https://www.08i8.com/ttkfzy/detail83716.html;转载请注明!