系列文章目录
Java学习笔记1—JVM虚拟机—1.1运行时数据区_摸金青年v的博客-优快云博客
Java学习笔记1—JVM虚拟机—1.2垃圾回收机制_摸金青年v的博客-优快云博客
目录
前言
探究虚拟机的垃圾回收机制的目的是,了解JVM中内存是如何动态释放的,需要知道哪些内存需要回收,什么时候触发回收,回收有哪些算法,目前有哪些垃圾回收器和特点,内存溢出有哪几种,发生内存溢出如何定位,后续如何改进,工作线程和回收线程之间的关系,如何支持高并发回收,会带来什么问题,值得我们思考。
一、对象垃圾回收机制
1. 如何判断对象可回收
1)引用计数法:引用时加一,失效时减一,为零时回收,会存在循环引用问题
2)可达性分析:GC Root对象作为起始点,当一个对象在引用路径(引用链)向上最终连接不到GC Root,认为对象不可达,则可回收。GC Root对象只能是: 虚拟机栈中引用的对象、方法区类静态属性引用的对象、常量引用的对象
本地方法栈中引用的对象
3)引用分强弱如何理解
引用越弱,表示越可以回收
强引用:表示只要强引用还存在,垃圾回收器就不回收,比如:Object object = new Object()
软引用:表示还有用但是非必须的对象。在系统即将内存异常之前,再回收一下这些对象,如果内存仍然溢出才抛异常
弱引用:表示非必须对象,被弱引用关联的对象只能生存到下一次垃圾回收发生之前,无论此时内存是否足够,都先回收这个
2. 垃圾回收机制有哪些
垃圾回收算法:标记-清除、复制、标记-整理
推荐阅读:Java虚拟机—GC垃圾回收机制_摸金青年v的博客-优快云博客
1)标记-清除特点:先标记可回收对象再清除,效率不高,产生内存碎片,影响后续内存分配,内存利用率低
2) 复制算法特点:先划分出一半内存,每次只使用一半,当内存无空间了,将使用的一半内存中存活对象复制到空闲的另一半内存,然后直接清理无空间的内存
缺点:内存压缩,GC频繁
优化:无需1:1划分,根据实际情况,新生代对象存活时间短,可以按8:1:1划分为较大的Eden区和两块较小的Survivor区,Eden区应该只会有少部分的存活对象
当回收时,将Eden区和Survivor区的存活对象,复制到未使用的Survivor区,然后清理下
但是我们保证不了每次的存活对象都小于10%,超出的对象会分配到老年代
因此,复制算法在对象存活率高,复制操作会变多,效率会变低
3)标记-整理特点:
对比标记-清除,标记操作相同,但是整理存活对象向一端移动,然后清理边界以外的内存
三种算法适用场景:
新生代:复制
老年代:标记-清除、标记-整理
3. 垃圾回收器的特点和选择
没有万能收集器,只有选择合适的收集器
关注要点:垃圾回收的线程的占用对工作线程的影响,考虑两点:暂停工作线程的时间、占用的内存
Serial收集器:单线程,缺点垃圾回收时,需要暂停所有工作线程,直到回收完成
ParNew收集器:多线程,还是要暂停所有工作线程
Parallel Scavenge收集器:目标是达到可控的吞吐量,比如:虚拟机运行100分钟,垃圾回收1分钟,吞吐量就是99%
控制垃圾回收时间参数
-XX: MaxGc-PauseMillis 最大垃圾收集停顿时间 (毫秒数)
-XX: MaxGc-PauseMillis 设置的小,是牺牲吞吐量和新生代空间换取的,GC会变频繁,停顿时间变少了,但是吞吐量性能也会降低
-XX: GCTimeRatio 吞吐量大小(0~100比率)
-XX: GCTimeRatio = 99 表示垃圾停顿时间为 1/(1+99)=1%
-XX: UseAdaptiveSizePolicy 表示开关开启后,虚拟机自动动态调节新生代等参数,自适应调节
CMS(Concurrent Mark Sweep)收集器:目标是尽可能的缩短工作线程停顿时间
4. 延伸思考
4.1 线程隔离的数据区需要考虑垃圾回收吗
答:不需要,此数据区需要的内存基本上编译期可知,方法结束和线程结束时,内存就被释放了
所以重点研究堆内存的对象回收,内存分配是动态不确定的
4.2 虚拟机吞吐量和停顿时间可以同时兼顾吗
答:不可以,吞吐量和停顿时间对立
吞吐量高:适用于后台运算,和用户交互少,对快速响应要求不高的应用
垃圾回收的停顿时间少:适用于用户交互频繁,高响应的应用
举例:低停顿时间是以牺牲吞吐量和新生代空间为代价的
收集300MB新生代肯定比收集500要快,但是收集会变得频繁,导致执行垃圾回收线程时间变多,即吞吐量降低
原来:10秒收集一次,每次停顿100ms
现在:5秒收集一次,每次停顿70ms,停顿时间变少,但是频繁了
总结
以上就是今天要讲的内容,本文介绍了虚拟机的垃圾回收机制