什么是GC垃圾回收呢。日常生活中我们去餐厅吃饭吃完饭,吃完饭走了餐具不用管,服务员在把餐具拿走,这是一种方式,服务员怎么知道他要来把餐具拿走呢,因为你走了,这个位置空了。服务员什么时候拿走餐具很重要,第一你没吃完,不会回收吧,第二很多人吃饭,你在里面,他也不一定回收吧,他会找一个合适的时机,一次性回收很多吧。

第二种方法:自己吃完饭把餐具带到回收的地方吧。

哪一种方式更好呢?

第一种方式自己也就是使用者不用管,服务员找一个合适的时机把垃圾回收了。

第二种自己去吧垃圾倒了。

在java中GC垃圾回收用的是第一种方式,系统找一个合适的时机把垃圾回收掉,我们不用手动去干预。这也是C#使用的垃圾回收机制。开发员人员只关心内存申请,不关心内存释放的问题

下面我们看一看垃圾回收GC回收算法。

1.1. 引用计数法

引用计数法是一种古老的垃圾收集方法,引用计数器实现很简单,对于一个对象A,有任何一个对象引用了A,那么A的计数器+1,引用失效时,A的计数器-1。当A的引用计数器是0的时候。那么A对象就不能被使用了。

引用计数法实现很简单就是额外的为每一个对象搞一个计数器,但是也有缺点:

1.引入计数器是解决一个问题又附加的引入一个问题。因为每次加减操作,可能影响系统性能。

2.无法处理循环引用问题,因此java的垃圾回收器中,没有使用这种算法。

下面举一个简单的例子:A对象和B对象,对象A中有B的引用,对象B中有A的引用。此时A和B两个对象的计数器都不是0,但在使用中没有其他对象引用A和B,说白了,A和B应该是被回收的对象,但是他们之间相互引用。计数器不为0,系统没有这种探针检测到循环引用,从而无法垃圾回收,引发内存泄露。

解释一个可达对象,不可达对象。

可达对象:通过根节点进行引用搜索,最终可以到达的对象。

不可达对象:通过根节点进行引用搜索,最终没有被引用的对象。

不可达的对象出现循环引用,它的引用计数器都不是0如下图所示:

1.2. 标记清除法

标记清除算法将垃圾的回收两阶段进行:标记阶段和清除阶段。

在标记阶段,顾名思义,就是从根节点开始标记可到达的对象。没有被标记的对象也就是没有被引用的对象那个就是垃圾对象。在第二个阶段也就是清除阶段,清除所有没有被标记的对象。标记清除算法。可能会产生空间的碎片,这也是这个算法的最大的问题。

如下图所示,使用标记清除算法对一块连续的内存空间进行回收,从根节点开始,所有的引用关系对象被标记为存活对象,

不可到达的对象被标记为垃圾对象,在清除阶段回收所有不可到达的对象,也就是没有被引用的对象。

如上图所示,回收后的空间是不连续的。在对象的堆空间分配中,大对象的内存分配,不连续的内存空间的效率低于连续的空间。这也是该算法的最大缺点。

标记阶段通过根节点查找所有可达对象,清除节点清除所有的不可达对象。完成系统的垃圾回收。

1.3. 复制算法

复制算法的原理:将分配的内存空间分为2块,每次只是用1块,在垃圾回收呢时,讲正在使用的内存中的存活对象复制到没有被使用的内存的一块,完成之后,清除正在使用的内存块中的所有对象,然后两个内存块交换,以此完成垃圾回收。

如果系统中的垃圾对象有很多,存活对象比较少,复制算法的优势就体现出来了。由于对象是在垃圾回收过程中统一被复制到新的内存空间,所以复制算法可以确保新的内存空间是没有碎片的。但是缺点就是,把内存分为了2块,不能充分的利用内存。

如下图所示:A、B两块相同的内存,A在进行垃圾回收的时候,讲存货的对象复制到B的空间,B的空间在复制后是连续的。复制完成之后,清除A。把B设置为当前使用的空间。

在java的新生代串行垃圾回收中,使用了复制算法,新生代之前的章节也讲过分为eden区域,from、to三个部分,之前也说过from、to是相等的可以替换的两个空间、地位相等、角色相等。from、to空间也被称之为survivor空间,英文解释为幸存者,用来存放没有被回收的对象,如下图所示。

新生代:堆空间中的年轻人,对象刚刚创建或者经历的垃圾回收次数不多的对象。

老年代:堆空间中的老年人,老年对象指经历了很多次垃圾回收亦然存活的对象,(看来大部分老年人存贮内存挺高的对象)。

在垃圾回收的过程中,eden空间存活的对象被复制到survivor空间,假如我们正在使用from空间,因此den空间存活的对象被复制到to空间。如果to空间内存满了,则对象直接进入老年代,可参考虚拟机参数设置的章节参考实例。此时eden空间和from空间剩余的对象就是垃圾对象,直接清空,to空间存放的就是存活的对象,这种改进之后的算法,保证了空间的连续性,这点很重要,又避免了大量的空间的浪费,因为这些空间是可以手动分配的。参考之前的章节。上图显示了复制算法的时机回收过程。

复制算法比较适合新生代,因为新生代垃圾对象一般比存活对象要多,这块区域,朝生夕死足矣。如果这个地方的对象存活就可能是常住内存的对象了。

1.4. 标记压缩法

上面也说了 压缩算法的使用前提是存活对象少、垃圾对象多的情况下使用。这种情况经常发生在新生代,在老年到就不合适了,因为老年代大部分都是存活对象,如果要使用复制算法,复制的成本很高,所以老年代使用的是其他的算法,老年人比较特殊嘛。

标记压缩算法是在标记清除算法基础之上优化了,标记压缩算法也是从根节点开始,对对象的可达性做一次扫描标记,之后不是直接清除未标记的对象,而是将所有的存活对象压缩到内存的一端,之后,清除边界外的所有空间,这样做的好处是避免了内存的不连续性,不需要内存设置两块相同的内存进行复制交换。所以压缩标记算法的性价比好啊。

标记压缩算法如下图所示完成垃圾回收。

标记压缩算法其实就是在标记清除算法完成之后,进行一次随便整理。所以称之为标记压缩算法。

1.5. 分区算法

上面说的都是出来堆空间的算法,对于栈是如何处理的呢。分区算法是将整个堆空间分成连续的不同的小区间,如下图所示。每一个小区间都是独立使用,独立回收,这样设计可以控制一次回收多少个区间。不回去全扫描。

一般来说在相同的条件下,堆空间越大,一次垃圾GC回收所需要的时间就越长,那么引起的副作用就是停顿时间越长,就是假死需要等待的时间就越长,使用分区算法的好处就是,合理的回收区间,不是扫描整个堆空间,从而减少一次GC产生的停顿。跟餐厅收餐具一样一样,分房间去收餐具,不是每次都按照顺序收餐具。

GC垃圾回收算法的更多相关文章

  1. Java GC 垃圾回收算法 内存分配

    垃圾回收(Garbage Collection, GC)是Java不同于c与c++的重要特性之一. 他帮助Java自动清空堆中不再使用的对象. 由于不需要手动释放内存,程序员在编程中也可以减少犯错的机 ...

  2. gc垃圾回收算法原理

    目录 三色标记法 标记-清扫(Mark And Sweep)算法 标记-清扫(Mark And Sweep)算法存在什么问题? 三色并发标记法 gc和用户逻辑如何并行操作? 进程新生成对象的时候,GC ...

  3. 6.GC垃圾回收算法和垃圾收集器的关系

    JAVAGC垃圾回收机制和常见垃圾回收算法 推荐博客:JVM垃圾回收机制和常见垃圾回收算法 JVM的内存结构.垃圾回收算法

  4. GC: 垃圾回收算法

    标记-清除算法标记-清除(Mark-Sweep)算法是最基础的算法,就如它的名字一样,算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象.之所以说 ...

  5. JVM中的垃圾回收算法GC

    GC是分代收集算法:因为Young区,需要回收垃圾对象的次数操作频繁:Old区次数上较少收集:基本不动Perm区.每个区特点不一样,所以就没有通用的最好算法,只有合适的算法. GC的4大算法 1.引用 ...

  6. 小师妹学JVM之:GC的垃圾回收算法

    目录 简介 对象的生命周期 垃圾回收算法 Mark and sweep Concurrent mark sweep (CMS) Serial garbage collection Parallel g ...

  7. 【C# .Net GC】垃圾回收算法 应用程序线程运行时,

    触发垃圾回收算法的条件 触发垃圾回收的条件 当满足以下条件之一时将发生垃圾回收: 操作系统报告低内存请看(将触发第2代垃圾回收). 这是通过 OS 的内存不足通知或主机指示的内存不足检测出来. 由托管 ...

  8. A6. JVM 垃圾回收算法(GC 算法)

    [概述] 常见的垃圾回收算法有:标记-清除算法.复制算法.标记-整理算法.分代收集算法. [标记-清除算法] 标记-清除算法是最基础的收集算法,如同它的名字一样,算法分为 “标记” 和 “清除” 两个 ...

  9. 深入理解java虚拟机【垃圾回收算法】

    Java虚拟机的内存区域中,程序计数器.虚拟机栈和本地方法栈三个区域是线程私有的,随线程生而生,随线程灭而灭:栈中的栈帧随着方法的进入和退出而进行入栈和出栈操作,每个栈帧中分配多少内存基本上是在类结构 ...

随机推荐

  1. ●POJ 2828 Buy Tickets

    题链: http://poj.org/problem?id=2828 题解: 线段树. 逆向考虑这个过程.最后的序列S共有n个元素. 先看最后一个人,如果他插入到第i位,那么他最终的位置就是当前序列S ...

  2. [UOJ UR #4追击圣诞老人]

    来自FallDream的博客,未经允许,请勿转载, 谢谢. 传送门 考虑直接维护一个堆,然后往里面丢链,并且取出k个堆顶就行了. 然后就需要分类讨论啥的,给你的三个点变成两条链,每次取出一条链之后选择 ...

  3. JSSDK实现微信自定义分享---java 后端获取签名信息

    一.首先说下关于微信Access_token的问题,微信Access_token分为2中: 1.授权token获取方式: 这种token需要code值(如何获取code值查看官方文档) "h ...

  4. 春招实习面经分享(已拿到腾讯春招Offer)

    十分幸运地收到了腾讯的Offer..回来报答一下各位牛客网的战友们,说起来也是有点运气成分,最后通过腾讯的内推收到了offer!之前也屡遭重创,阿里的内推一面挂了(寒假过早地投简历,电话面试应对地不太 ...

  5. Codeforces Round #396(Div. 2) A. Mahmoud and Longest Uncommon Subsequence

    [题意概述] 找两个字符串的最长不公共子串. [题目分析] 两个字符串的最长不公共子串就应该是其中一个字符串本身,那么判断两个字符串是否相等,如果相等,那么肯定没有公共子串,输出"-1&qu ...

  6. Docker镜像的实现原理

    Docker 镜像是怎么实现增量的修改和维护的? 每个镜像都由很多层次构成,Docker 使用 Union FS 将这些不同的层结合到一个镜像中去. 通常 Union FS 有两个用途, 一方面可以实 ...

  7. Python3 标准库概览

    操作系统接口 os模块提供了不少与操作系统相关联的函数. >>> import os >>> os.getcwd() # 返回当前的工作目录 'C:\\Python ...

  8. Linux 虚存 linux2.6内核特性

    一.大型页面的支持 当代计算机体系结构大都支持多种页面大小,例如,IA-32体系结构支持4KB或4MB的页面, Linux操作系统只是将大型页面用于映射实际的内核映像.大型页面的使用主要是为了改进高性 ...

  9. 20160227.CCPP体系详解(0037天)

    程序片段(01):01.一对一模式.c+02.中介者模式.c+03.广播模式.c 内容概要:事件 ///01.一对一模式.c #include <stdio.h> #include < ...

  10. 计算机网络之动态主机配置协议DHCP

    为了将软件协议做成通用的和便于移植,协议软件的编写者不会把所有细节都固定在源代码中,而是把协议软件参数化,这就使得在很多台计算机上使用同一个经过编译的二进制代码成为可能. 一台计算机和另一台计算机的区 ...