专栏首页吉林乌拉垃圾收集算法

垃圾收集算法

垃圾收集器是Java虚拟机中自带的功能,它的目的是帮助我们管理内存,正是因为有它的存在所以,我们在开发时,基本不用考虑内存溢出等问题。基本不用考虑不代表,一定不会遇到内存溢出等问题,在上一篇中我们用简单的方法模拟了一些内存溢出的问题,在这一篇我们将重点分享一下,Java中垃圾收集器的一些实现算法知识,了解这方面的知识有助于,在内存溢出时,快速的解决问题。垃圾收集器的主要功能有3个。

  • 哪些内存需要回收
  • 什么时候回收
  • 如何回收

实现上述的3个功能,有很多种算法,下面我们具体看一下每一种算法的利与弊

  • 引用计数算法

给对象添加一个引用计数器,每当有对象引用时,计数器的值就加1。当引用失效时,计数器的值就减1。这样当对象的计数器为0时,该对象就是没有被引用的对象,也就是可以被回收的对象了。但这种算法有一个弊端,就是如果对象循环引用时,这两个对象的引用计数器的值都不为0,这样,垃圾收集器就无法准时的回收它们了。正是因为有这样的弊端,所以在Java虚拟机中的垃圾收集器并不是采用这种算法实现的。

  • 可达性分析算法

通过称为“GC Roots”的对象作为起始点,从这些节点开始搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链时,就说明当前对象是不可用的。 也就是可以被垃圾收集器回收的对象。

在Java中,可以做为GC Roots的对象主要包括下面几种:

  • 栈中的引用对象
  • 方法区中类静态属性引用对象
  • 方法区中常量引用对象

上面我们提到了引用,下面我们看一下引用的介绍。引用:如果某类型中的数据存储的数值代表的是另外一块内存的起始地址,就称这块内存代表着一个引用。在Java中引用主要包括4种它们分别是:

  • 强引用:强引用是永远不会被垃圾收集器回收的对象。类似于new 一个新对象时创建的引用。
  • 软引用:软引用是用来描述一些有用但并非必需的对象。当系统将要发生内存溢出时,会把这些对象列为待回收对象,但不会马上回收,当垃圾收集器执行第二次时回收此范围的对象。
  • 弱引用也是用来描述非必需对象的,它的强度比软引用更弱。当垃圾收集器执行时,优先回收此类型的引用对象。无论当前内存是否足够,都会回收。
  • 虚引用也称为幽灵引用或者幻影引用,它是最弱的一种引用关系。虚引用的唯一目的就是能在这个对象被垃圾收集器回收时收到一个系统通知。

在可达性分析算法中当真真正正确认一个对象是否可以回收,通常要经历两次标记过程。当对象进行分析后,发现没有与GC Roots相连接的引用链,那么它还会对已经标记的对象,进行最后一次筛选,目的是判断对象是否可以执行finalize()方法。 当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,则虚拟机将回收此对象。如果对象覆盖了finalize()方法,并且在finalize()方法中重新创建了新引用,那么虚拟机将在第二次标记时,将此对象移除出“即将回收”的集合。如果对象在虚拟机执行finalize()方法时还没有任何引用链,那此对象将基本被回收。finalize()方法是对象防止被垃圾收集器回收的最后机会。

  • 标记-清除算法

算法主要分为标记和清除两个阶段。首先要标记出所有需要被回收的对象,然后在所有对象标记完成后,在统一回收已标记的对象。这种算法有两个弊端:一个是效率问题,标记和回收时所消耗的时间比较长。别一个弊端就是在回收时因为对象有可能不是连续的,所以导致回收后的内存也是不连续的,也就是会造成很多内存碎片,内存碎片大多有一个问题,就是如果虚拟机要分配大的对象时,由于无法找到满足条件的足够的连续内存,所以不得不在一次触发一次垃圾收集,所以性能较慢。

  • 复制算法

在标记-清除算法中因为有效率等问题,所以,复制算法出现了。它基本逻辑是将内存分为大小相等的两块,每次只使用其中的一块。 当这一块的内存用完时,就将还存活着的对象(也是采用标记的方式)复制到另外一边,然后再把这一块的内存回收。 这样使回收后的内存不会在有内存碎片了。 但这种方式也有弊端就是它将内存划分了两半,每次使用时只能用一半内存来存储数据。还有一个弊端就是,因为要复制已经存活的对象,如果存活的对象比较多时,复制时所消耗的时间比较大,效率比较低。

  • 标记-整理算法

标记-整理算法也是先采用标记方式,找出所有存活的对象,然后不在是复制方式,而是将所有存活的对象都向一端移动,然后在回收边界以外的内存。

  • 分代收集算法

分代收集算法是根据对象的存活周期的不同将内存划分为不同的几块。 一般是把堆分为新生代和老年代。 在新生代中因为大部分对象都不是存活的,所以只要进行少量的复制即可,所以采用复制算法。 而老年代中因为大部分对象都是存活的,如果拷贝的话,效率会有影响,于是就就采用“标记—清理”或者“标记—整理”算法来进行回收。

本文分享自微信公众号 - 吉林乌拉(jilinwulacom)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-06-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Spring框架中的WebApplicationContext接口

    这一篇我们介绍一下WebApplicationContext接口的知识,看WebApplicationContext接口的名字我们应该可以得知,这个接口就是专门...

    吉林乌拉
  • IOC容器-构造函数注入、属性注入、接口注入

    今天我们详细了解一下spring框架中IOC的作用。IOC的英文名叫Inverse of Control,中文名叫控制反转也可以叫依赖注入,是spring容器的...

    吉林乌拉
  • 设计模式之观察者模式

    今天我继续和大家分享一下设计模式中的知识,今天我们来看一下观察者模式。观察者模式也可以叫发布订阅模式,在实际的场景中有很多时候会遇到这种设计模式。在现实的生活中...

    吉林乌拉
  • 面试题:讲讲Java垃圾回收机制

    本文内容是基于 JDK 1.6 的,不同版本虚拟机之间也许会有些许差异,但不影响我们对JVM垃圾回收机制的整体把握和了解。

    用户1263954
  • JVM学习笔记——垃圾收集器与内存分配策略(1)

    上一篇文章介绍了java运行时内存的各个区域,其中虚拟机栈,程序计数器,本地方法栈三个区域随线程而生,随线程而灭。栈中的栈帧随着方法的进入和退出有条不紊的执行着...

    用户1665735
  • Java虚拟机内存管理(四)—垃圾回收

    Java 虚拟机作为运行 Java 程序抽象出来的计算机,具有内存管理的能力,像内存分配、垃圾回收等这些相关的内存管理问题,Java 虚拟机都会帮我们解决,所以...

    Wizey
  • 深入了解JVM垃圾收集器

    程序计数器、JVM栈、本地方法栈这三个内存区域和线程是一一对应的,并且每一个线程的这三个区域相互独立互不干扰。他们都随着线程的产生而产生,线程的灭亡而灭亡。JV...

    大闲人柴毛毛
  • 深入理解Java虚拟机(JVM) --- 垃圾收集算法(中)

    由于方法区中存放生命周期较长的类信息、常量、静态变量. 因此方法区就像堆的老年代,每次GC只有少量垃圾被清除.

    JavaEdge
  • 疯狂Java笔记之Java的内存与回收

    对于JVM的垃圾回收机制来说,是否回收一个对象的标准在于:是否还有引用变量引用改对象?只要有引用变量引用对象,垃圾回收机制就不会回收它。

    HelloJack
  • 编程思想 之「字符串」

    字符串(String)对象是不可变的,把String对象作为方法的参数时,其实都是复制一份引用,而该引用所指的对象一直待在单一的物理位置上,从未动过。我们可以给...

    CG国斌

扫码关注云+社区

领取腾讯云代金券