JVM知识汇总
2020-08-18 18:24:08 6 举报
AI智能生成
JVM1.7
作者其他创作
大纲/内容
JVM(1.7)
JVM内存区域
方法区
用于存放被JVM加载的类信息、常量、静态变量、即时编译器编译后的代码等
堆
新生代YoungGeneration
Eden
Survivor(From)
Survivor(To)
老年代OldGeneration
程序计数器:当前线程执行字节码的行号指示器
虚拟机栈(JVM执行Java方法)
java方法执行的内存模型,每个方法执行都会创建一个栈帧(局部变量表、操作数栈、动态链接、方法出口),每个方法从开始调用到结束都对应一个栈帧在虚拟机栈中入栈到出栈的过程。
本地方法栈(JVM执行本地方法)
HotSpot把本地方法栈和虚拟机栈合二为一
直接内存(Direct Memory)
jdk1.4的NIO,可以使用native函数直接分配堆外内存,受本机总内存和处理器寻址空间的限制
线程共有
线程私有
JVM内存溢出
OutOfMemoryError:Java heap space
最大堆、最小堆、新生代:-Xms512M -Xmx512M -Xmn128M
虚拟机栈/本地方法栈
StackOverflowError
每个线程可使用内存:-Xss256K
OutOfMemoryError:unable to create new native thread
OutOfMemoryError:PermGen space
JVM设置最小最大:-XX:PermSize=64M -XX:MaxPermSize=128M
直接内存
at sun.misc.Unsafe.allocateMemory(Native Method)
元空间(java1.8)
java.lang.OutOfMemoryError: Metadata space
-XX:MetaspaceSize:128M -XX:MaxMetaspaceSize=128M
子主题 6
GC overhead limit exceeded
垃圾回收
判断对象已死
引用计数算法
给对象添加一个引用计数器,每当一个地方引用它时计数器加1;引用失效计数器减1,计数器为0说明不再引用
优点:实现简单,判定效率高
缺点:无法解决对象相互循环引用的问题
可达性分析算法
当一个对象到GC Roots没有引用链相连(GC Roots到这个对象不可达)时,证明此对象不可用
GC Roots种类
虚拟机栈(栈帧中的本地变量表)中引用的对象
方法区中的静态属性引用的对象
方法区中的常量引用的对象
本地方法栈中JNI(Native方法)引用的对象
引用
强引用
Object object=new Object();
软引用
SoftReference<Object> object=new SoftReference<Object>(new Object());
弱引用
WeakReference<Object> object=new WeakReference<Object>(new Object());
虚引用
finalize()
对象是否覆盖finalize方法
是:jvm执行finalize()方法
否:JVM回收对象
JVM是否执行过该对象的finalize方法
是:JVM回收对象(每个对象finalize方法只执行一次)
否:JVM执行finalize()方法
垃圾收集算法
标记清除算法
缺点:1、标记和清除效率都不高;2、标记、清除之后会产生大量不连续的内存碎片
复制算法(新生代)
Eden:Survivor:Survivor=8:1:1
分配担保:如果Survivor没有足够空间来存放上次新生代GC存活下来的对象,它们将通过分配担保机制进入老年代
缺点:对象存活率高时,复制效率较低
标记整理算法(老年代)
先执行标记-清除,让所有的存活对象都向一端移动,最后清理掉边界以外的内存
回收方式
单线程
并行
并发
垃圾收集器
新生代
Serial
特点:单线程收集;标记-复制算法
场景:Client模式下默认新生代收集器;单核机器
ParNew
特点:多线程并行收集;标记-复制算法;其他特点与Serial相似
缺点:在单CPU场景效果不突出
场景:用户交互;配合CMS垃圾收集器
Parallel Scavenge
特点:目标在于达到可控吞吐量(吞吐量=用户代码运行时间/(用户代码运行时间+垃圾收集时间));标记-整理
场景:高效利用CPU,后台运算且不需要太多交互
老年代
CMS
特点:最短回收停顿时间;标记-清除
步骤
初始标记:标记GC Roots直接关联的对象,速度快
并发标记:GC Roots Tracing过程,好市场,与用户进程并发工作
重新标记:修正并发标记期间用户进程继续运行而产生变化的标记,耗时比初始标记长,但远小于并发标记
并发清除:清除标记的对象
缺点
对CPU资源敏感
无法回收浮动垃圾
标记-清除算法,会产生内存碎片,可以通过参数开启碎片的合并整理
Serial Old
特点:Serial的老年代版本,单线程;标记-整理
场景:1.5之前与Parallel Scavenge配合使用;作为CMS的后备预案
Parallel Old
特点:标记-整理;多线程
场景:为了替代Serial Old与Parallel Scavenge配合使用
G1
特点:将整个Java堆划分为多个大小相等的独立区域Region,跟踪各个Region里面的垃圾堆积的价值大小,在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region
初始标记:标记GC Roots直接关联的对象
并发标记:对堆中对象进行可达性分析,找出存活对象,耗时长,与用户进程并发工作
最终标记:修正并发标记期间用户进程继续运行而产生变化的标记
筛选回收:对各个Region的回收价值排序,然后根据期望的GC停顿时间制定回收计划
垃圾收集器搭配关系
分支主题
垃圾回收过程
大多情况下对象在Eden分配,当Eden没有足够空间时将发起一次Minor GC
当Eden执行Minor GC后还不足以为对象分配空间,大对象直接进入老年代,可以用参数设置大对象直接进入老年代,避免频繁Minor GC
如果对象在Eden出生,发生MinorGC后仍然存活,且能被Survivor容纳,年龄加1,达到一定年龄进入老年代,默认15
占Survivor空间一半以上且年龄相等的对象,大于等于该年龄以上的对象直接进入老年代
发生Minor GC之前会先检查老年代最大可用连续空间是否大于新生代所有对象总空间,如果大于说明MinorGC安全;否则会判断是否允许担保失败,如果允许担保失败,判断老年代最大连续空间是否大于历次晋升到老年代对象的平均大小,如果大于则尝试MinorGC,否则执行FullGC
类加载
类的生命周期
加载(Loading)
通过一个类的全限定名来获取定义此类的二进制字节流
将二进制字节流代表的静态存储结构转化为方法区的运行时数据结构
在内存中生成一个代表该类的java.lang.Class对象,作为方法区这个类各种数据的访问入口
连接
验证(Verification)
文件格式验证
元数据验证
字节码验证
符号引用验证
准备(Preparation)
正式为类变量分配内存并设置初始值
解析(Resolution)
把间接引用转换为直接引用
初始化(Initialization)
执行<cliinit>(),初始化类变量、静态代码块
使用(Using)
卸载(Unloading)
Java类加载器
启动类加载器(Bootstrap ClassLoader)
扩展类加载器(Extension ClassLoader)
应用程序类加载器(Application ClassLoader)
自定义类加载器(User ClassLoader)
性能优化
常见问题
CPU Load过高导致系统不可用或tps急剧降低
YoungGC次数频繁
FullGC次数频繁
FullGC时间长
PermSpace GC次数频繁
内存泄漏、内存溢出
调优参考数据
系统运行日志
异常堆栈
GC日志
线程快照(threaddump/javacore文件)
堆转储快照(heapdump/hprof文件)
调优工具
jdk命令行工具
jps查看系统内所有HotSpot进程
jinfo显示虚拟机配置信息
jstat收集虚拟机运行数据
jmap生成指定进程堆转储快照(heapdump文件)
jhat分析heapdump文件
jstack显示虚拟机线程快照
可视化工具
jconsole和jvisualvm查看内存回收情况
BTrace跟踪调试方法
jprofiler监控每个类的内存占用
MAT工具分析内存占用
优化方案
JVM配置
-Xms和-Xmx的值设置成相等
新生代尽量设置大一些
实现层面
避免创建过大的对象及数组
避免同时加载大量数据
集合中的对象用完后及时清空
在合适场景使用软引用、弱引用
尽量避免长时间等待外部资源(数据库、网络、设备资源等)
设置合理的线程数
JVM内存模型
volatile
保证不同线程对共享变量操作时的可见性
禁止指令重排序
点个赞吧❤
0 条评论
回复 删除
下一页