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