JVM是如何回收垃圾的?

Posted lllllLiangjia

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JVM是如何回收垃圾的?相关的知识,希望对你有一定的参考价值。

目录

前言

内存泄漏与内存溢出的区别

如何找到垃圾?

可达性分析算法--目前JVM使用的

GC Roots对象包括

引用计数法--扩展

如何清除垃圾?

标记-复制算法

缺点:

适用范围:

标记-整理算法

缺点:

适用范围:

标记-清除算法

缺点:


前言

JVM如何回收垃圾其实就是GC操作,那GC操作的步骤是什么?

我们可以将它分为两个步骤:找垃圾和清除垃圾

 

说之前我们先明确两个概念

内存泄漏与内存溢出的区别

内存泄漏:已经使用过的内存没有及时的清空处理,长时间占用内存,导致内存空间不足,而出现内存溢出。

内存溢出:要求使用的空间超过系统能给的,系统不能满足需求,于是溢出。

 

如何找到垃圾?

可达性分析算法--目前JVM使用的

从GC Roots的根对象作为起点开始搜索,搜索过程所走的路径成为引用链,如果某个对象到GC Roots间没有任何引用链相连,那随时可被GC回收。

 

GC Roots对象包括

  1. 虚拟机栈中引用的对象,譬如各个线程被调用方法堆栈中使用到的参数、局部变量、临时变量
  2. 方法区中类静态属性引用的对象,譬如Java类的引用类型静态变量
  3. 方法区中的常量引用对象,譬如字符串常量池里的引用
  4. 所有被同步锁持有的对象

 

 

可达性算法判为不可达对象,也不是非死不可,宣告一个对象的死亡,至少要经过两个标记过程:

如果对象在进行可达性分析后没有发现与GC Roots相连接的引用链则第一次标记,随后进行筛选,判断是否有该对象的类重写了finalize()方法,如果没有则直接回收。如果有,将对象放在一个F-Queue队列中,之后去执行他们的finalize()方法,如果在这个方法中重新与引用链上的任何一个对象建立关联即可。

再回收时,如果第二次进行了标记,则直接回收

 

引用计数法--扩展

每个对象都有一个引用计数器,当对象被引用一次,计数器就加1,当对象引用时效一次就减,当计数器为0,意味着对象是垃圾对象,可以被GC回收。

 

注:环形垃圾无法回收

 

如何清除垃圾?

标记-复制算法

将内存一分为二,将有用的对象拷贝到新的一半内存区域

 

缺点:

将内存缩小为了原来的一半,空间浪费太多了

 

适用范围:

新生代区域使用,两个survivor区域每回收一次数据,都将其中的一个survivor区域有用的数据放到另一个survivor区域内。

 

标记-整理算法

首先标记出所有存活的对象,让他们都向内存空间一端移动,然后直接清理掉边界以外的内存。

 

缺点:

这种对象的移动操作必须全程暂停用户应用程序才能进行,这样的停顿被描述为“Stop The World”

 

适用范围:

老年代区域使用

 

标记-清除算法

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

缺点:

造成的问题碎片化严重

以上是关于JVM是如何回收垃圾的?的主要内容,如果未能解决你的问题,请参考以下文章

JVM垃圾回收(下)

必知必会JVM垃圾回收——对象搜索算法与回收算法

必知必会JVM垃圾回收——对象搜索算法与回收算法

关于JVM内存垃圾回收性能调优总结篇

如何修改jvm虚拟机垃圾回收器

JVM垃圾回收机制