【Java】浅谈Java的垃圾回收(GC)及常用的垃圾回收算法

垃圾回收机制

在Java语言中,垃圾回收是一个非常重要的概念,它的主要作用是回收程序中不再使用的内存,我们通常说的gc是英文单词garbage collection,也就是垃圾回收器的意思。

在我们以前使用c语言或者c++进行开发的时候,开发人员必须仔细的管理好内存的分配与释放,如果忘记或者错误的释放内存,往往会导致程序不能够正常运行, 甚至是崩溃。

为了减轻开发人员的工作, 同时增加系统的安全性与稳定性,Java语言提供了垃圾回收器来自动检测对象的作用域。

具体而言,垃圾回收器主要完成三方面工作:第一为对象分配内存 ;第二确保对象的引用 ;第三对于没有被引用的对象要被回收。

那么,对于GC垃圾回收器来说,他回收的依据就是:在我们内存中 如果某个对象没有被其他任何对象或者变量引用的话,则这个对象被认为是垃圾 ,可以被回收。

垃圾回收器的存在 ,一方面呢把开发人员从释放内存的复杂工作中解脱出来, 提高了开发人员的效率;另外一方面, 对开发人员屏蔽了对内存的控制,也避免了开发人员因为错误的操作内存导致程序的崩溃, 进而呢提高了稳定性。

但是对于垃圾回收器来说, 为了实现垃圾回收,那么,我们的JVM必须要对内存进行跟踪, 释放没用的对象,在完成内存的释放后, 还需要对我们JVM中的堆进行碎片处理。

那这些操作必然会增加JVM的负担, 进而呢降低程序的执行效率。对于垃圾回收器来说, 它是一把双刃剑,一方面我们对于程序开发, 它提供了便捷 ,另外一方面正是因为垃圾回收要不断的对我们内存进行监听,所以执行效率相对于c或者c++语言来说要低一些,但是随着技术发展以及软硬件的规格在不断提高, 这两者的差距在不断的缩小。

对于垃圾回收器来说,他使用的是有向图的方式 ,来记录和管理堆内存中的所有对象,通过有向图可以识别哪些对象是可达的, 哪些对象是不可达的。对于可达的对象, 我们予以保留, 对于不可达的对象 ,视为垃圾, 将会被垃圾回收器处理掉。
在这里插入图片描述
就像当前的这个例子 ,我们在main方法中有i1和i2两个变量, 指向了1号对象;而2号对象 尽管他被创建了, 但是如果没有任何变量去引用它的话,很快这个2号变量就会被垃圾回收掉。

垃圾回收(GC)算法

在底层,垃圾回收器对于对象的回收来说也是有一定的算法的,尽管原理是指是否可达,但是在常用的垃圾回收器,它包含了五种常用的算法。

这里呢 我给大家来介绍一下,在面试的时候, 面试官可能会问你一个对象是怎么被回收的,如果当时你只回答一个对象没有被引用的时候他就被回收, 那显然这个结果太low了。其实面试官底层问你的含义是你了解几种垃圾回收的算法。对于JVM,他怎么就知道这个对象有没有引用呢 ,这里我给大家介绍常用的五种算法。这五种算法作为扩展的知识,了解一下, 最好能记住名字就可以了。

首先, 第一种算法:

引用计数算法

引用计数算法作为一种最简单的但是也是效率最低的方法 ,它的主要原理是 :在我们JVM堆中保存的每一个对象都有一个被引用的计数器, 当有一个变量去引用到这个对象的时候, 这个计数器就会加1 ,当变量被释放或者是断开这个引用的时候 ,计数器就会减1 ,如果这个对象的引用计数器变成了零,则代表这个对象可以被垃圾回收 。但是呢 ,这里有一个问题, 如果两个对象彼此都互相引用的话 ,就会形成一个循环 ,我们称之为循环引用 。对于循环引用, 使用计数器算法是无法解决的

第二种叫做

跟踪回收算法

跟踪回收算法是利用JVM维护的对象引用图 ,我们可以形象的看成JVM在内存中画了一张图, 每个对象之间, 他们彼此都是像蜘蛛网一样彼此依赖和引用 ,从根结点开始 ,遍历对象的引用图同时标记可以被遍历到的对象 ,当遍历结束以后,未被标记的对象, 那就是 ,不能够使用的对象,可以被回收了 。

第三种

压缩回收算法

压缩回收算法是指将我们JVM堆中活动的对象放到一个集中的区域中 ,然后在堆的另外一端, 留出一大块空闲的区域, 这就相当于对堆中的碎片进行处理。 其实大家很好理解 ,在我们平时打扫卫生的时候, 如果地面特别脏乱的话, 我把办公桌先搬到墙角, 留出大片的、 没有任何东西的空间, 之后 ,把地面上的垃圾进行清扫 ,之后我再把办公桌搬回到原位, 这就是压缩回收算法的精要所在。 但是呢, 对于压缩回收算法 ,他看起来很简单, 但是对于性能上来说 ,它的损失还是比较大的 ,因为每一次我都得搬这张办公桌再把它搬回来是吧 。

第四种叫做

复制回收算法

复制回收算法的主要思路呢, 就是把堆呢分成两个相同大小的区域, 在任何时刻 ,只有其中的一个区域被使用, 直到这个区域被消耗完, 此时垃圾回收器就会中断程序的运行, 通过遍历的方式, 把所有活动的对象复制到另外一个区域中。 在复制的过程中 ,这些对象呢是紧密的挨在一起的 ,从而呢 可以消除了我们在内存中产生的碎片 。当复制结束以后, 接着也行, 直到这块区域被使用完, 然后再采用上面的办法进行垃圾回收 。那么 这种办法呢, 它的优点是在垃圾回收的同时 也完成了对对象的重新布置和安排, 因为在内存中我们这些对象都是紧密连接的, 所以它的访问效率和寻址效率都是非常高的 ,而且一次性的解决了内存碎片的问题。 但是呢 ,这么做也要付出很大的代价,因为对于指定大小的堆来说 ,我们需要两倍大小的内存空间。 同时呢 ,由于在内存中调整的过程 ,需要中断当前程序的执行, 进而呢, 降低了程序的执行效率

最后一种呢 是叫

按代回收算法

按代回收算法, 它呢是我们现在一个主流的回收算法, 大家一定要记住这个名字, 叫做按代回收算法。 他针对于前面的复制回收算法呢, 解决了一些他的缺点, 复制回收算法它的主要缺点集中在每次算法执行的时候都要把所有处于活动状态的对象复制一份 ,这样效率肯定很低 。在我们的程序中, 如果按照对象的生命周期的长短来进行区分的话, 绝大多数对象它的生命周期都很短, 比如说, 在我们方法中所声明的一些对象 ,方法结束, 这个对象就被释放了。 那么, 只有很少的一部分的对象拥有较长的生命周期 。比如说我们的全局变量, 比如说, 我们需要一直持有引用的这些变量, 它才具有较长的生命周期。 但是这只是一小部分, 基于这个特点呢 ,按代回收算法进行了优化。 他的主要思路呢, 就是把堆分成两个或者多个子堆每个子堆都视为一代 。算法在运行的过程中优先收集这些年幼的 ,也就是年轻的对象 。对于一些对象经过多次收集仍然存活的, 则把这些对象移到高一级的堆里。 也就是说 ,我们一开始的时候, 很多对象都是刚刚被创建, 那么他呢是每次都会被扫描的, 但是比如说扫描了十次20次以后, 这个对象会一直存在, 我就认为他这个对象是稳定的 ,把他放到一个更高级别的堆里面去。 而这个更高级别的堆呢 ,它扫描的频度相对是比较低的 。根据这种按代分类的做法, 我们可以把一些 稳定的不常用的类减少它的扫描次数, 进而呢缩小了我们扫描的范围, 从一定程度上也就相当于提高了我们回收的效率。

以上 就是垃圾回收中最常用的五种算法 ,用大白话的方式给大家做了一个简单的介绍, 有一个了解就可以了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值