JVM垃圾回收机制

JVM垃圾回收机制

一、回收堆区

垃圾回收器在堆进行垃圾回收前,首先要判断这些对象那些还存活,那些已经“死去”。判断对象是否已“死”有如下几种算法:

1.引用计数法

给对象增加一个引用计数器,每当有一个地方引用它时,计数器就+1;

当引用失效时,计数器就-1;

任何时刻计数器为0的对象就是不能再被使用的,即对象已“死”。

引用计数法实现简单,判定效率也比较高,在大部分情况下都是一个比较好的算法。

但是,在主流的JVM中没有选用引用计数法来管理内存,最主要的原因是引用计数法无法解决对象的循环引用问题。

2. 可达性分析算法

在上面讲了,Java并不采用引用计数法来判断对象是否已“死”,而采用“可达性分析”来判断对象是否存活。

通过一系列称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称为“引用链”,当一个对象到 GC Roots 没有任何的引用链相连时(从 GC Roots 到这个对象不可达)时,证明此对象不可用。以下图为例:

<span>JVM垃圾回收机制</span>

在Java语言中,可作为GC Roots的对象包含以下几种:

  1. 虚拟机栈(栈帧中的本地变量表)中引用的对象。
  2. 方法区中静态属性引用的对象
  3. 方法区中常量引用的对象
  4. 本地方法栈中(Native方法)引用的对象

引用

JDK1.2以前,Java中引用的定义很传统: 如果引用类型的数据中存储的数值代表的是另一块内存的起始地址,就称这块内存代表着一个引用。

这种定义有些狭隘,一个对象在这种定义下只有被引用或者没有被引用两种状态。

JDK1.2之后,Java对引用的概念做了扩充,将引用分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)和虚引用(Phantom Reference)四种,这四种引用的强度依次递减。

1.强引用

类似于”Object obj = new Object()”这类的引用,只要强引用还存在,垃圾回收器永远不会回收掉被引用的对象实例。

当内存空 间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。

2.软引用

如果一个对象只具有软引用,那就类似于可有可无的生活用品。

如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。

软引用可用来实现内存敏感的高速缓存。

举例:查看网页,可能后退,那么刚才的网页要不要一直存储,一直存储就是强引用,不存储就是回收,那么折中一下,于是产生了弱引用,当内存空间足够时,就不回收,不足时,再回收。这个根据内存敏感程度而变化而决定是否缓存,就是内存敏感的高速缓存。

3.弱引用

对象拥有更短暂的生命周期。

在gc线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间是否充足,都会回收它的内存。

由于gc是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。

4.虚引用

就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。

如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。

作用: 虚引用主要用来跟踪对象被垃圾回收的活动

区别: 虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。

当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。

如果程序发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

3.真正判决

要宣告一个对象的真正死亡,至少要经历两次标记过程

如果对象在进行可达性分析之后发现没有与GC Roots相连接的引用链,那它将会被第一次标记并且进行一次筛选。

筛选的条件是此对象是否有必要执行finalize()方法。

​ 没必要:没有覆盖finalize()方法finalize()方法已经被调用过一次了

审判

如果这个对象被判定为有必要执行finalize()方法,那么这个对象将会被放置在一个叫做F-Queue的队列之中,并在稍后由一个虚拟机自动建立的、低优先级的Finalizer线程去执行它

如果对象在finalize()中成功拯救自己:与引用链上的任何一个对象建立起关联关系

那在第二次标记时它将会被移除出”即将回收”的集合,也就暂时逃脱死亡的命运了。

如果对象这时候还是没有逃脱,那基本上它就是真的被回收了。

二、回收方法区

方法区(永久代)的垃圾回收主要收集两部分内容:废弃常量无用类。

废弃常量:

没有任何一个String对象引用常量池中的”abc”常量,也没有其他地方引用这个字面量,如果此时发生GC并且有必要的话,这个”abc”常量会被系统清理出常量池。

常量池中的其他类(接口)、方法、字段的符号引用也与此类似。

无用类

1.该类的所有实例都已经被回收(即在Java堆中不存在任何该类的实例)
2.加载该类的ClassLoader已被回收
3.该类对应的Class对象没有任何其他地方被引用,无法在任何地方通过反射访问该类的方法

三、垃圾回收算法

1.标记-清除算法

首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象

“标记-清除”算法的不足主要有两个

  1. 效率问题:标记和清除这两个过程的效率都不高
  2. 空间问题:标记清除后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行中需要分配较大对象时,无法找到足够连续内存而不得不提前触发另一次垃圾收集。

<span>JVM垃圾回收机制</span>

2.复制算法(新生代回收算法)

它将可用内存按容量划分为大小相等的两块,每次只使用其中一块。

当这块内存需要进行垃圾回收时,会将此区域还存活着的对象复制到另一块上面,然后再把已经使用过的内存区域一次清理掉。

因为复制过去后,另一边的内存肯定是连续的了,此时再把使用过得内存区域清理,从而达到了整理的效果。

也就是伊甸园区移动到survive0和survive1区的算法。

但是,伊甸园区的对象都是朝生夕死的,所以并不需要1:1的空间,所以出现了8:1:1的默认比例

<span>JVM垃圾回收机制</span>

3.标记整理算法(老年代回收算法)

复制收集算法在对象存活率较高时会进行比较多的复制操作,效率会变低。因此在老年代一般不能使用复制算法。

而是采用标记整理算法

标记过程仍与“标记-清除”过程一致,但后续步骤不是直接对可回收对象进行清理,而是让所有存活对象向一端移动,然后直接清理掉除存活对象以外的内存。流程图如下:

<span>JVM垃圾回收机制</span>

4.分代收集算法

就是将堆区分开,不同的位置采用不同的算法

新生代中,每次垃圾回收都有大批对象死去,只有少量存活,因此我们采用复制算法;

老年代中对象存活率高,就必须采用”标记-清理”或者”标记-整理”算法。

四 .Minor GC、Major GC、Full GC的区别?

Minor GC 又称为新生代GC 指的是发生在新生代的垃圾回收操作(包括Eden区和Survivor区)。

当年轻代内存空间被用完时,就会触发垃圾回收。这个垃圾回收叫做Minor GC。

Major GC通常是跟full GC是等价的,收集整个GC堆。

但因为HotSpot VM发展了这么多年,外界对各种名词的解读已经完全混乱了

Full GC定义是相对明确的,就是针对整个新生代、老生代、元空间(metaspace,java8以上版本取代perm gen)的全局范围的GC。

针对HotSpot VM GC来看

它里面的GC其实准确分类只有两大种:

Partial GC:并不收集整个GC堆的模式

  • Young GC:只收集年轻代的GC
  • Old GC:只收集老年代的GC。只有CMS的concurrent collection是这个模式
  • Mixed GC:收集整个年轻代以及老年代的GC。只有G1有这个模式

Full GC:收集整个堆,包括young gen、old gen、perm gen(如果存在的话)等所有部分的模式。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/115159.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 亿图永久激活码-激活码分享

    (亿图永久激活码)好多小伙伴总是说激活码老是失效,太麻烦,关注/收藏全栈君太难教程,2021永久激活的方法等着你。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.cn/100143.html0BXA05X8YC-eyJsaWNlbnNlSW…

  • Java Interface用法

    Java Interface用法Javainterface有多种用法,最常见的就是通过interface传递数据第一种publicinterfaceIData{voidvalue(Stringstr);}publicclassClassA{publicvoidsendData(IDataidata){idata.value(“ThisisClassA’valu

  • 整除的尾数_整除数

    整除的尾数_整除数整除的尾数时间限制:1000 ms | 内存限制:65535 KB难度:0描述一个整数,只知道前几位,不知道末二位,被另一个整数除尽了,那么该数的末二位该是什么呢?输入输入数据有若干组,每组数据包含二个整数a,b(0输出对应每组数据,将满足条件的所有尾数在一行内输出,格式见样本输出。同组数据的输出,其每个尾数之间空一格,行末没有空格。样例输入

  • EVE模拟器的使用-带图超详细(学网络用)「建议收藏」

    EVE模拟器的使用-带图超详细(学网络用)「建议收藏」文章目录EVE模拟器的安装EVE模拟器的使用登陆添加一个实验退出一个实验实验分类创建任务(添加路由交换机)选择型号和种类说明修改已创建种类参数界面放大和缩小方式一方式二种类(设备)之间连线和删除连线连线删线添加注释信息(描述)设备开机开启单个设备开启所有设备设备功能配置软件抓包EVE模拟器的安装EVE模拟器的下载及安装见:EVE模拟器的使用登陆根据上面安装步骤进入到这个界面以后:用户名:admin密码:unl(小写L)登陆方式:Nativeconsole登陆成功以后就是这个界面:添

  • matplotlib-bilibili,抖音很火的动态数据视频自动生成(第四节)-视频,语音合成

    matplotlib-bilibili,抖音很火的动态数据视频自动生成(第四节)-视频,语音合成

  • kali linux木马免杀工具

    kali linux木马免杀工具1.VenomShellcodeGenerator

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号