JVM原理
2021-03-16 19:58:57 198 举报
AI智能生成
JVM原理
作者其他创作
大纲/内容
核心参数
永久代/方法区
jdk1.7
-XX:MaxPermSize
永久代最大大小
-XX:PermSize
永久代大小
jdk1.8
-XX:MaxMetaspaceSize
永久代最大大小
-XX:MetaspaceSize
永久代大小
老年代
-XX:MaxTenuringThreshold
默认15岁
多少岁进入老年代
Java堆内存
-XX:SurvivorRatio=8
默认Eden区比例为80%
jdk1.7
-Xms
Java堆内存的大小
-Xmx
Java堆内存的最大大小
-Xmn
Java堆内存中的新生代大小
jdk1.8
-XX:PretenureSizeThreshold
大对象阈值
-XX:InitialHeapSize
初始堆大小
-XX:MaxHeapSize
最大堆大小
新生代
-XX:NewSize
初始新生代大小
-XX:MaxNewSize
最大新生代大小
线程方法栈
-Xss
每个线程的栈内存大小
GC回收器
ParNew
-XX:+UseParNewGC
指定新生代垃圾回收器为ParNew
-XX:ParallelGCThreads
可以调节ParNew的垃圾回收线程数
CMS
-XX:+UseConcMarkSweepGC
指定老年代垃圾回收器为CMS
-XX:-CMSParallelRemarkEnabled
手动开启并发标记
-XX:+CMSClassUnloadingEnabled
垃圾回收会清理持久代,移除不再使用的classes
-XX:LargePageSizeInBytes
JVM内存分页大小
-XX:+UseFastAccessorMethods
-XX:+UseCMSInitiatingOccupancyOnly
-XX:SoftRefLRUPolicyMSPerMB
-XX:CMSInitiatingOccupancyFaction
jdk 1.6默认是92%
设置老年代占用多少比例的时候触发CMS垃圾回收
-XX:+UseCMSCompactAtFullCollection
默认打开
意思是Full GC之后要再次进行stop the world,然后进行碎片整理
-XX:CMSFullGCsBeforeCompation
默认0
执行多少次Full GC之后再执行一次内存整理
G1
-XX:+UseG1GC
自动用堆大小除以2048
-XX:MaxGCPauseMills
默认200ms
设置GC时让系统停顿的时间
-XX:InitiatingHeapOccupancyPercent
默认值45%
新生代+老年代的混合垃圾回收触发比例
老年代z占据堆内存的45%的Region的时候,会尝试触发一个混合回收
-XX:G1MixedGCCountTarget
默认8次
混合回收阶段分多少次进行回收
XX:G1HeapWastePercent
默认5%
Region回收都是基于复制算法进行的
-XX:G1MixedGCLiveThresholdPercent
默认85%
回收Region的时候必须是存活对象低于85%的Region才可以进行回收
打印日志
-XX:+PrintGCDetils
打印详细的gc日志
-XX:+PrintGCTimeStamps
这个参数可以打印出来每次GC发生的时间
-Xloggc:gc.log
这个参数可以设置将gc日志写入一个磁盘文件
OOM
-XX:+HeapDumpOnOutOfMemoryError
OOM的时候自动dump内存快照出来
-XX:HeapDumpPath=/usr/local/app/oom
把内存快照放到那个目录
GC回收
对象引用类型
强引用
软引用
弱引用
虚引用
stop the world
禁止运行不能创建对象
可达性分析算法
GC ROOT
JVM规范中,局部变量就是可以作为GC Roots
静态变量也可以看做是一种GC Roots
方法的局部变量、类的静态变量给引用了,就不会回收他们
垃圾回收器
新生代
Serial
单线程执行
ParNew
执行步骤
1.多个垃圾回收线程
多线程并发执行
默认跟CPU核数一样的线程
2.垃圾回收器
3.垃圾回收算法
复制算法
执行步骤
进入stop the world
1.标记Eden区、Survivor区中的存活对象
2.全部转移到另一个Survivor区
3.一次性清空掉Eden区、Survivor区中的存活对象
老年代
Serial Old
单线程执行
CMS
多线程并发执行
回收算法
标记整理算法
执行步骤
1.初始标记
进入stop the world
标记除所有GC Roots直接引用的对象
速度很快
2.并发标记
可以随意创建对象
对所有对象进行GC Roots追踪
由于是并发运行,所以不会对系统造成影响
非常耗时
3.重新标记
再次进入stop the world状态
对第二阶段中被系统程序运行变动过的小数对象进行标记
速度很快
4.并发清理
跟着系统运行,清理掉之前标记为垃圾的对象
非常耗时
G1垃圾回收器
总区域分为2048个Region
优点
设置垃圾回收的预期停顿时间
回收价值
大对象Region
判定:大对象占Region的50%大小
过大的对象会横跨多个Region来存放
新生代
默认新生代对堆内存的占比是5%
-XX:G1NewSizePercent
新生代的占比不会超过60%
也会分Eden区和2个Survivor区
采用复制算法
老年代
老年代占堆内存45%的时候触发Mixed垃圾回收
回收算法
新生代+老年代混合垃圾回收
执行步骤
1.初始标记
进入stop the world
标记除所有GC Roots直接引用的对象
速度很快
2.并发标记
可以随意创建对象
对所有对象进行GC Roots追踪
由于是并发运行,所以不会对系统造成影响
非常耗时
3.重新标记
再次进入stop the world状态
对第二阶段中被系统程序运行变动过的小数对象进行标记
速度很快
4.混合回收
跟着系统运行,清理掉之前标记为垃圾的对象
回收Region基于复制算法进行的
把存活对象放去其他Region区,然后把这个Region中的垃圾对象全部清理掉
Concurrent Mode Failure问题
触发Full GC的运行期间,如果还有新生代对象要进入老年代,但老年代不够空间存放的情况下
1.立马进入Stop the World
2.切换CMS为Serial Old垃圾回收器,禁止程序运行
3.单线程进行老年代垃圾回收
4.回收对象后,再让系统继续运行
生产配置
4GB机器
-Xms3072M -Xmx3072M -Xmn2048M -Xss1M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=5 -XX:PretenureSizeThreshold=1M -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFaction=92 -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0
类加载
时机
java代码使用类的时候会进行类加载
加载步骤
加载
验证
.class文件加载到内存之后,会先验证是否符合格式规范
准备
分配对象的内存空间,类变量初始化默认值
解析
把符号引用直接替换为直接引用的过程
初始化
发现类的父类还没初始化,会先初始化父类
类变量进行逻辑赋值
使用
卸载
类加载器
双亲委派机制
先找父加载器,找不到再由儿子来加载
可以避免多层级的加载器结构重复加载某些类
1.启动类加载器
Bootstrap ClassLoader
负责加载我们在机器上安装的Java目录下的核心类
java目录下的lib目录
2.扩展类加载器
Extension ClassLoader
加载lib\ext目录中的类
3.应用程序类加载器
Application ClassLoader
这类加载器负责加载“ClassPath”环境变量所指定的类,可以理解为去加载写好的Java代码
4.自定义类加载器
JVM运行原理
执行方法代码
把方法的栈帧压入Java虚拟机栈
不断调方法,不断压栈
方法执行完,栈帧出栈
JVM区域
程序计数器
当前线程所执行的字节码的行号指示器
分支、循环、跳转、异常处理、线程恢复等基础功能都依赖计数器完成
唯一不会发生 OOM 的内存区域
本地方法栈
与 Java 虚拟机栈相似,为虚拟机使用到的本地(Native)方法服务,例如xx.hashcode()底层方法
JAVA虚拟机栈
栈帧
局部变量表
操作数栈
动态链接
方法出口
StackOverflowError
线程请求的栈深度大于虚拟机所允许的深度
OutOfMemoryError
如果Java虚拟机栈容量可以动态扩展,当栈空间无法申请到足够内存时抛出
HotSpot 的栈容量不可以动态扩展,所以只要申请栈空间成功就不会有 OOM,但是如果申请时就失败,仍然是会出现 OOM 异常的
堆内存
新生代
Eden区
默认占 80%
Survior区
Survior 1区
默认占 10%
Survior 2区
默认占 10%
TLAB(Thread Local Allocation Buffer)
线程私有的分配缓存区,以提升对象分配时的效率
是否使用 TLAB:-XX:+/-UseTLAB
Minor GC/Young GC
对老年代空间大小做检查
老年代空间分配担保规则
-XX:-HandlePromotionFailure
默认打开,会进行第二步检查,
jdk1.6之后废弃
jdk1.6后默认判断规则
老年代可用空间 > 新生代对象总和
老年代可用空间 > 历次Minor GC升入老年代对象的平均大小
老年代有空间
1.Minor GC过后,剩余的存活对象的大小,是小于Survivor区的大小的,那么此时存活对象进入Survivor区域即可
2.Minor GC过后,剩余的存活对象大小,是大于Survivor区域的大小,但是小于老年代可用内存的大小,此时就直接进入老年代即可
老年代无空间
3.很不幸,Minor GC过后,剩余的存活对象的大小,大于了Survivor区域的大小,也大于了老年代可用内存的大小,此时老年代都放不下这些存活对象了,就会触发一次“Full GC”
进入老年代
躲过gc 15次,年龄达到15岁的对象
-XX:MaxTenuringThreshold
设置多少岁进入老年代,默认15岁
动态对象年龄判断
Survior区的一批对象总大小大于这块Survior区域的内存大小的50%,那么大于等于这批年龄的对象直接进入老年代
大对象直接进入老年代
-XX:PretenureSizeThreshold
设置字节数,大于这个字节数的对象直接进入老年代
老年代
每次Full GC后都会产生大量的内存碎片,太多的内存碎片会导致增加频繁的Full GC
永久代/方法区
存储数据
已被虚拟机加载的类型信息
常量
静态变量
即时编译器编译后的代码缓存
JDK 1.7
永久代PermGen space
将字符串常量池、静态变量等从永久代移出
静态变量移到堆中 Class 对象内
JDK 1.8
元数据区Metaspace
类的方法代码,变量名,方法名,访问权限,返回值等
永久代中剩余的内容(主要是类型信息)
内存回收目标
主要是针对常量池的回收和类型的卸载
运行时常量池
特点:运行期间将新的常量放入池中
例子:String 类的 intern() 方法
直接内存
生产调优
jstat -gc PID
查看gc情况的命令
分析GC频率
jmap -heap PID
jmap -histo PID
分析JVM中各种对象内存空间占用大小
jmap -dump:live,format=b,file=dump.hprof PID
jmap生成堆快照
jhat dump.hprof -port 7000
0 条评论
下一页