大家好,金三银四马上就要到了,趁着这个周末赶紧复习一下JVM的一些相关知识,XiXi在工作期间很少接触到需要用到JVM知识的活,基本上都是业务上的CRUD。所以这里只能根据自己日常生活中学习过的视频或者看过的文章进行整理,目的也是应付面试。
垃圾回收的目标区域
JVM的运行时数据区有:
-
堆 -
方法区 -
虚拟机栈 -
本地方法栈 -
程序计数器
其中需要进行垃圾回收的内存区域有2个:堆和方法区。对于方法区而言,回收工作主要是对类的卸载,无用类的判断相当麻烦,且此内存区域回收效益也不高。所以垃圾回收动作主要针对的就是堆
堆相关知识
那么说到堆,就要简单的复习一下堆的基本知识了。
-
堆的分区:新生代和老年代,其默认比例是1:2 -
新生代:Eden区、S0区和S1区,其默认比例是8:1:1 -
老年代 -
默认情况下对象年龄达到 15(经历15次新生代的GC),就会从新生代晋升到老年代 -
堆中存放对象、数组,JDK7时HotSpot虚拟机将静态变量、字符串常量池由方法区移动到堆
堆相关的JVM参数
-Xms512m:初始堆大小 -Xmx1g:最大堆大小 -Xmn512m:新生代大小,优先级高 -XX:SurvivorRatio=8:调整Eden和Survivor区比例 -XX:NewRatio=2:调整新生代和老年代比例 -XX:+UseAdaptiveSizePolicy:自适应调节,默认开启,会导致新生代并非8:1:1 -XX:MaxTenuringThreshold=15:指定晋升老年代年龄阈值 -XX:+UseTLAB:使用TLAB
java -XX:+PrintFlagsFinal #查看所有参数最终值
java -XX:+PrintFlagsFinal -version | grep [参数名] #筛选指定参数查看
如何判断垃圾
我就是垃圾😂[手动笑哭]
判断垃圾的方式有以下两种:
-
引用计数:对象通过一个变量记录正在被引用次数,为0时就是垃圾 -
优点:简单、速度快 -
缺点:循环引用问题无法解决 -
可达性分析:通过GC Roots(根对象),搜索可以被引用到的对象,这些对象不是垃圾 -
优点:解决循环引用问题 -
缺点:略慢
GC Roots对象
哪些对象可以作为GC Roots?我是记不住了
-
在虚拟机栈(栈帧中的本地变量表)中引用的对象,譬如各个线程被调用的方法堆栈中使用到的
参数、局部变量、临时变量等。
-
在方法区中类静态属性引用的对象,譬如Java类的引用类型静态变量。
-
在方法区中常量引用的对象,譬如字符串常量池(String Table)里的引用。·在本地方法栈中JNI(即通常所说的Native方法)引用的对象。
-
Java虚拟机内部的引用,如基本数据类型对应的Class对象,一些常驻的异常对象(比如NullPointExcepiton、OutOfMemoryError)等,还有系统类加载器。
-
所有被同步锁(synchronized关键字)持有的对象。
-
反映Java虚拟机内部情况的JMXBean、JVMTI中注册的回调、本地代码缓存等。
垃圾回收算法
下面我们来看一看,垃圾回收的算法,主要有:
-
标记-清除(Mark-Sweep) -
复制(Copying) -
标记-整理(Mark-Compact) -
分代收集算法 -
分区收集算法
标记-清除
先用可达性算法标记出存活对象(并非垃圾对象) 清除未被标记的垃圾对象
美国五星上将麦克阿瑟评论:实现简单,但是会存在内存碎片问题
复制
将内存区域分成A和B两块区域,先使用其中一块区域,如A A区域用可达性算法标记出存活对象(并非垃圾对象) 将A区域中存活对象复制到区域B中,并清空区域A A和B身份调换
美国五星上将麦克阿瑟评论:内存利用率低,适合新生代用
标记-整理
先用可达性算法标记出存活对象(并非垃圾对象) 清除未被标记的垃圾对象 进行内存整理
美国五星上将麦克阿瑟评论:比较耗时,适合老年代
分代收集算法
按照新生代和老年代对象存活的特点,来采用不同的垃圾回收算法
-
新生代:采用复制算法 -
老年代:采用标记-整理算法
针对垃圾回收的目标区域不同,又有不同的名称
-
部分GC:针对堆 -
Minor GC:新生代的GC -
Major GC:老年代的GC -
Mixed GC:新生代+部分老年代 -
Full GC:堆+方法区
分区收集算法
将堆划分成一块块的小内存区域(分区),针对这些小区域进行收集。这样每次可以只收集几块小区域,而非整个堆,以此来减少GC停顿时间。
对于小块区域的收集,最终应该还是应用复制、标记整理或标记清除这三个基本算法
垃圾回收器
红线:JDK8时废弃Serial+CMS和ParNew+Serial Old CMS+Serial Old这两个老年代收集器组合是为了给CMS兜底 JDK14时,CMS废弃,Parallel Scavenge+Serial Old组合废弃
Serial和Serial Old
Serial:新生代、复制算法、串行 Serial Old:老年代、标记整理算法、串行
如何指定:-XX:+UseSerailGC,自动使用Serial+Serial Old组合
ParNew
新生代、复制算法、多线程GC
相关参数:
-XX:+UseParNewGC:新生使用ParNewGC+老年代Serial Old -XX:ParallelGCThreads=3:执行线程数量
Parallel Scavenge和Parallel Old
Parallel Scavenge:新生代、复制算法、多线程GC Parallel Old:老年代、标记整理算法、多线程GC 重要特性:吞吐量优先,吞吐量=用户程序执行时间/(用户程序执行时间+GC时间)
相关参数:
-XX:+UseParallelGC:开启新生代Parallel Scavenge -XX:+UseParallelOld:开启老年代Parallel Old 以上配置开启其中一个,另一个就默认开启
-XX:ParallelGCThreads=3:执行线程数量 -XX:GCTimeRatio=N:N取值(0,100),GC时间占单位时间N% -XX:MaxGCPauseMillis:最大GC暂停时间优先级高于 -XX:GCTimeRatio
-XX:+UseAdaptiveSizePolicy:开启自适应调节,新生代及内部区域分配、老年代、晋升年龄都会自动调整,以满足堆大小、吞吐量、停顿时间的平衡点
CMS
Concurrent-Mark-Sweep:实现了用户线程和GC线程并发执行 老年代、标记-清除、并发 重要特性:低延迟
CMS的垃圾回收分为4个阶段
-
初始标记:STW发生但短暂,标记出GC Roots直接引用的对象 -
并发标记:从初始标记后的对象出发,开始遍历整个对象图。此阶段与用户线程并发执行 -
重新标记:进入STW,目的是为了修改并发标记过程中产生变动的对象 -
并发清理:清除死亡对象,此阶段也与用户线程并发执行
初始标记和重新标记阶段都会产生STW,但不会太长 CMS执行老年代收集时需预留一部分内存,因为是并发的,GC过程中还要响应用户线程。中途要失败则切换Serial Old
相关参数:
-XX:+UseConcMarkSweepGC:开启CMS -XX:CMSInitiatingoccupanyFraction:触发CMS阈值 -XX:+UseCMSCompactAtFullCollection:Full GC后是否压缩内存 -XX:CMSFullGCsBeforeCompaction=N:多少次Full GC后执行压缩 -XX:ParallelCMSThreads=N:CMS线程数,默认是(ParallelGCThreads+3)/4
参考资料
-
尚硅谷:《尚硅谷宋红康JVM全套教程(详解java虚拟机)》
原文始发于微信公众号(溪溪技术笔记):JVM-垃圾回收算法和垃圾回收器
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/219735.html