一、数据区

讲解垃圾回收算法之前,先来看一下Java虚拟机内存运行时的几个数据区:

1、堆(heap)

最大的一块区域,用于存放对象实例和数组,对于所有线程来说,它是全局共享的。而我们所说的GC主要是清理堆中实例对象所占的内存空间。

2、栈(stack)

又叫做虚拟机栈,主要存储基本数据类型,对象的引用,私有线程等。

3、方法区(Method Area)

主要存储类加载器(ClassLoader)加载的类信息,可以理解为已经编译好的代码的存储区。class的一些常量、静态常量会放在这里。

4、各数据区的联系

当我们建立一个对象时(通常使用new关键字创建对象),会在堆中开辟一块空间,同时会将这块空间的地址作为引用保存到栈中,如果该对象的生命周期结束了,那么引用就会从栈中出栈。例如:

Object obj = new Object();

上面的代码左边的Object obj 等于在栈中申请了一块内存,也就是对类对象的引用,而 new Object()则是生成了一个实例对象,=则是可通过obj访问Object对象的内容。在Java里都是通过引用来操纵对象的。

二、对象存活的判断方法

1、引用计数法

引用计数法的概念:在堆中存储的对象,它会维护一个counter计数器,如果有一个引用指向它时,则counter计数器加一,如果一个引用关系失效,则counter计数器减一。当该对象的counter值变为0时,则说明该对象没有任何引用,处于可以回收的状态,可以被垃圾回收器回收。

但是Java虚拟机(JVM)并没有使用该算法来判断对象是否存活,原因是该算法有一个非常明显的缺陷: 对于对象间的相互引用问题,该算法无法识别出对象已处于可被回收的状态,导致相互引用的对象都无法被垃圾管理器回收。

举一个简单的例子:

public class ReferenceCount {public ReferenceCount instance = null;public static void main(String[] args) {ReferenceCount referenceA = new ReferenceCount();ReferenceCount referenceB = new ReferenceCount();referenceA.instance = referenceB;referenceB.instance = referenceA;referenceA = null;referenceB = null;}
}

main函数的第一行,ReferenceCount referenceA = new ReferenceCount();生成了一个ReferenceCount对象(我们称之为对象1,下同),并被referenceA所引用,此时对象1的counter值为1。 接着main函数的第二行,ReferenceCount referenceB = new ReferenceCount();生成了一个ReferenceCount对象(我们称之为对象2,下同),并被referenceB所引用,此时对象2的counter值为1。 main函数的第三行,referenceA.instance = referenceB;的意思是将referenceB的值赋值给referenceA.instance对象,也就是对象1引用了对象2,也就是对象2被对象1所引用,这时对象2的counter值为2。 main函数的第四行,referenceB.instance = referenceA;的意思是将referenceA的值赋值给referenceB.instance对象,也就是对象2引用了对象1,也就是对象1被对象2所引用,这时对象1的counter值为2。 main函数的第五行,referenceA = null;将对象1的引用referenceA置为null,这时对象1的counter值减一,值为1。 main函数的第六行,referenceB = null;将对象2的引用referenceB置为null,这时对象2的counter值减一,值为1。 照正常的逻辑,到了这里对象1和对象2都已经变得不可用了,应该被回收才对,但是由于它们各自的引用计数counter值不为0,所以不能被回收。如下图所示,当referenceA和referenceB引用去掉时,对象1和对象2还有相互间的引用,导致counter值为1,因此不能被回收。


2、可达性分析算法

第二种用来判断一个对象是否存活的算法是可达性分析算法。它的概念是:通过一系列的GC Root对象作为起点,从这些对象搜索引用的对象,形成多条引用链。如果一个对象到GC Root是不可达的,则说明这个对象不可用,则可以被回收了。 当我们分析一个对象是否是垃圾对象时,会去找该对象是否被其他对象引用,以此类推,如果最终能够找到一个GC Root对象,则证明该对象是可用的,否则则是垃圾对象。 那么哪些对象可以作为GC Root呢?GC Root对象包括下面几种:

  • 虚拟机栈中引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法栈中JNI(Native方法)引用的对象。

2.1 finalize()方法最终判定对象是否存活

即使在可达性分析算法中不可达的对象,也并非一定会被回收。对象真正被回收需要至少经历两次被标记的过程。 由上面的可达性分析算法可知,在对象进行可达性分析算法后,没有发现一条可以和GC Root对象的引用链,则会被标记一次

  • 第一次标记并执行一次筛选操作 筛选的条件是此对象是否有必要执行finalize()方法。当对象有复写finalize()方法,或者finalize()方法没有被虚拟机调用过,则说明是有必要执行finalize方法的。反之,当对象没有复写finalize()方法,或者finalize()方法以及被调用过了,则对象会被回收。
  • 第二次标记 如果对象被判定为有必要执行finalize()方法,则该对象会被放置到一个名为F-Queue的队列中,然后虚拟机会建立一个低优先级的线程Finalizer去执行对象的finalize()方法。finalize()方法是对象逃脱被回收命运的最后的机会,因为Java虚拟机会在稍后对F-Queue队列中的对象进行第二次标记,如果对象在finalize方法中重新与引用链上的任意一个对象关联上,例如将自己赋值给某个类变量或者某个对象的成员变量即可,这样在第二次标记时它就会被移出”即将被回收“的集合,如果对象在这个时候再次被标记了,则它就会被回收。 具体的流程图如下所示(图片引用自https://blog.csdn.net/ochangwen/article/details/51406779):

三、垃圾回收算法

1、标记-清除算法

标记-清除算法是最基本的垃圾回收算法,其中的做法分为两个步骤:第一步是首先发生GC操作时,将可以被回收的对象进行标记处理。第二步是回收第一步中被清除的对象所占的空间。 算法演示参考下图:


从上图中可以看出,标记-清除算法的优点是该算法比较简单,但是其缺点是内存碎片化严重,发展到后续可能会找到大对象找不到可存放的空间的问题。

2、复制算法

为了解决上述标记-清除算法的缺点而提出来的复制算法。复制算法的做法是将内存分为大小相等的两块,每次只使用其中的一块,当一块内存满了之后,将这块内存中还存活的对象复制到另外一块内存。然后将之前那块内存进行清理操作。 算法演示参考下图:


复制算法虽然不容易产生碎片,但是最大的问题是可用内存被压缩到了原来的一半,而且如果存活对象比较多的话,则复制算法的效率会下降。

3、标记-整理算法

标记整理算法综合了上述两种算法,第一阶段和标记-清除算法一样,首先将需要清除的对象进行标记,第二阶段略微不一样的是,在标记后并不是清除垃圾对象,而是将存活对象向内存的一端进行移动,移动完毕后,清除剩下的内存空间。 算法演示参考下图:


4、分代收集算法

分代收集算法是目前大部分Java虚拟机所采取的一种垃圾回收算法。即是根据对象存活的生命周期将内存空间划分为新生代和老生代和永生代。我们这里只讨论新生代和老生代。 新生代的特点是每次垃圾回收都会有大部分的对象会被回收,而老生代的特点是每次垃圾回收仅仅有少部分的对象会被回收。所以根据不同内存区域采用不同的垃圾回收算法。


新生代: 一般新生代会划分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden空间和其中的一块Survivor空间。可以看到Eden空间比Survivor0和Survivor1空间大,这是因为在新生代中大部分的对象被创建后很快就会被GC,所以Survivor空间不用分配太多的空间。

新生代中垃圾回收算法的具体操作步骤如下: 当进行回收时,将Eden空间和Survivor0空间中还存活的对象复制到另一块Survivor1空间中,然后清除Eden和Survivor0的空间,之后就使用Eden和Survivor1这两块空间。 当进行下一次垃圾回收时,将Eden和Survivor1的空间还存活的对象复制到Survivor0,然后清除Eden和Survivor1的空间。以此类推,每次总有一个Survivor空间是空的。 当然,如果目标Survivor空间无法存储Eden和Survivor存活的所有对象时,会将这些对象存储到老生代。 当对象中Survivor区躲过一次GC时,其年龄就会加1,当到达一定的年龄后,会将其移动到老生代。

老生代: 在新生代中经历了N次垃圾回收后仍然存活的对象,就会被放到老生代中。因此,可以认为老生代中存放的都是一些生命周期较长的对象。所以在老生代中一般所采取的垃圾回收算法是标记-整理算法

四、参考文章

  • https://blog.csdn.net/qq_33048603/article/details/52727991
  • https://blog.csdn.net/quinnnorris/article/details/75040538
  • https://blog.csdn.net/u011277123/article/details/53908315

JVM的垃圾回收策略相关推荐

  1. JVM分代垃圾回收策略的基础概念

    JVM分代垃圾回收策略的基础概念 由于不同对象的生命周期不一样,因此在JVM的垃圾回收策略中有分代这一策略.本文介绍了分代策略的目标,如何分代,以及垃圾回收的触发因素. 文章总结了JVM垃圾回收策略为 ...

  2. jvm垃圾回收策略之标记清除

    垃圾回收指的是对 jvm堆内存的回收. 一. java虚拟机栈 二.本地方法栈(Native Method Stack) 本地方法栈的功能和特点类似于虚拟机栈,均具有线程隔离的特点以及都能抛出Stac ...

  3. ReviewForJob——java虚拟机的垃圾回收策略(个人总结)

    理解jvm的垃圾回收策略,需要解决以下3个问题 问题1:哪些内存需要回收? 问题2:什么时候进行回收? 问题3:怎样来回收? [解决问题1]哪些内存需要回收? jvm的内存区域有5大块: 1)程序计数 ...

  4. JAVA之JVM分代垃圾回收策略(一)

    一.为什么要分代 分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一样的.因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率. 在Java程序运行的过程中,会产生大量的对 ...

  5. 漫画:什么是 JVM 的垃圾回收?

    作者 | 鸫鸫鹅,小灰 来源 | 程序员小灰(ID:chengxuyuanxiaohui) -----  第二天  ----- ------------ 下面我们一起来研究这三个问题. 问题1:哪些是 ...

  6. 垃圾回收策略和算法,看这篇就够了

    作者 | Craig无忌 来源 | 程序员大帝(ID:kingcoding) 前言 回收,旧手机,旧冰箱,旧空调,旧洗衣机,电瓶车摩托车,自行车,报纸,塑料...... 还记得小时候,我喝完的饮料瓶子 ...

  7. java垃圾回收 分代_Java分代垃圾回收策略原理详解

    一.为什么要分代 分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一样的.因此,不同生命周期的对象可以采取不同的收集方式,以便提高回收效率. 在Java程序运行的过程中,会产生大量的对 ...

  8. 漫画:什么是JVM的垃圾回收?

    -----  第二天  ----- ------------ 下面我们一起来研究这三个问题. 问题1:哪些是需要回收的? 首先我们需要知道如何哪些垃圾需要回收?判断对象是否需要回收有两种算法.一种是引 ...

  9. jvm垃圾回收机制_深入理解JVM的垃圾回收机制

    ​如何判断对象已"死" Java堆中存放着几乎所有的对象实例,垃圾回收器在堆进行垃圾回收前,首先要判断这些对象那些还存活,那些已经"死去".判断对象是否已&qu ...

最新文章

  1. 常用的数据结构-链表
  2. 各种Web漏洞测试平台
  3. python怎么学最快-怎么快速自学python
  4. html js 做的小游戏,用js做一个小游戏平台 (一)
  5. BestCoder Round #67 (div.2) 1001——N bulbs
  6. 论文阅读之ALBERT
  7. 保存文件_正确保存Zbrush文件
  8. .NET性能分析最佳实践之:如何找出使用过多内存的.NET代码(基础篇)
  9. SecureCRT安装(5)
  10. SQL语句学习1——SHOW命令
  11. Delphi7 动态数组
  12. 零和收益DEA模型(ZSG-DEA)的求解
  13. ERP巨头温州困局解读
  14. 李沐基于Pytorch的深度学习笔记(1)
  15. 计算机网络基础之域名系统
  16. 重构于 Vite:我如何做 SSG、静态资源发布以及自动化部署
  17. 值得一看的文章——阳光心态
  18. Echarts3实例 map地图值渲染
  19. 在我们使用vue-admin-templete进行二次开发的时候,我们会发现有些是英文,比如分页里面的每页尺码。
  20. 2021-08-06,拼多多平台API,item_search - 根据关键词取商品列表

热门文章

  1. 让员工满意才是最佳雇主
  2. ubuntu系统引导修复
  3. 【论文笔记】MiniSeg: An Extremely Minimum Network for Efficient COVID-19 Segmentation
  4. Android之ListView实现
  5. 目标检测网络之SPP-net详解
  6. 三步换系统 win10到Ubuntu20.04
  7. Sql语句:时间模糊查询
  8. 品达物流TMS项目_第12章 项目总结
  9. crontab 分时日月周的例子
  10. 最小系统计算机组成部分,单片机最小系统的组成及其原理解析