如何判定哪些对象可回收?

可达性分析算法

       在主流的JVM实现中,都是通过可达性分析算法来判定对象是否存活的。可达性分析算法的基本思想是:通过一系列被称为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots对象没有任何引用链相连,就认为GC Roots到这个对象是不可达的,判定此对象为不可用对象,可以被回收。

在Java中,可作为GC Roots的对象包括下面几种:

1、虚拟机栈中引用的对象;

2、方法区中类静态属性引用的对象;

3、方法区中常量引用的对象;

4、本地方法栈中Native方法引用的对象。

垃圾回收算法

标记清除算法

标记阶段:标记的过程其实就是前面介绍的可达性分析算法的过程,遍历所有的GC Roots对象,对从GC Roots对象可达的对象都打上一个标识,一般是在对象的header中,将其记录为可达对象;

清除阶段:清除的过程是对堆内存进行遍历,如果发现某个对象没有被标记为可达对象(通过读取对象header信息),则将其回收。

对于没有标记的对象则会放到一个单向的空闲列表free_list里面,这样当新建对象需要分配内存时我们就可以从free_list里面取出合适的分块。

缺点

1、内存碎片化。因为对象不移动,所以导致块是不连续的,容易出现空闲内存很多,但分配大对象时找不到合适的块。

2、分配速度慢。其操作仍是一个O(n)的操作,最坏情况是每次都要遍历到最后。同时因为碎片化,大对象的分配效率会更慢(相对影响较小)

3 、破坏了用户程序的局部性,破坏了缓存命中率

复制算法

从GC Roots根节点开始遍历,将根节点及其引用的子节点全部复制到TOSPACE,每复制一个对象,就把 free 指针向后移动相应大小的位置。

在执行Copying GC时,如果一个对象被拷贝了,那么该对象的mark word可以存储它的forwarding pointer指向新的拷贝

(不用把堆都遍历一遍)

1、将内存缩小为原来的一半,浪费了一半的内存空间,代价太高;

2、如果对象的存活率很高,极端一点的情况假设对象存活率为100%,那么我们需要将所有存活的对象复制一遍,耗费的时间代价也是不可忽视的。

标记整理

  • 标记阶段:选取gc根对象。从这些对象开始向下遍历其子对象,最终可能会形成一个又向有环图。在此图中的对象就是活动对象,也就是将要压缩的对象。

  • 整理阶段:将对象向着一端移动,移动后对象的相对顺序不变,但是对象紧临。

    • 设置forwarding指针

    • 搜索整个堆,给活动对象设置forwarding的位置
      set_forwarding_ptr(){scan = new_address = $heap_startwhile(scan < $heap_end)if(scan.mark == TRUE)scan.forwarding = new_addressnew_address += scan.sizescan += scan.size
      }

      更新指针

    • 需要让每一个对象知道移动后子对象将来的位置。因此需要修改指针
      adjust_ptr(){//更改根的指针for(r : $roots)*r = (*r).forwardingscan = $heap_startwhile(scan < $heap_end)//如果标记过,就将子对象设置为子对象将来的位置(forwarding)if(scan.mark == TRUE)for(child : children(scan))*child = (*child).forwardingscan += scan.size
      }

      移动对象

    • 移动对象,过程很简单,每个对象都知道要去的地址,只需要顺序移动便可,然后清除之前的标记。注意要顺序移动,不然会覆盖掉活动对象move_obj(){scan = $free = $heap_startwhile(scan < $heap_end)if(scan.mark == TRUE)new_address = scan.forwardingcopy_data(new_address, scan, scan.size)new_address.forwarding = NULLnew_address.mark = FALSE$free += new_address.sizescan += scan.size
      }

时间复杂度

  1. 标记阶段:遍历所有的存活对象,与活动对象数成正比
  2. 设置forwarding指针阶段:扫描整个堆
  3. 更改子对象指针阶段:扫描整个堆
  4. 移动阶段:扫描整个堆

优点

  • 相比于标记清除与引用计数:没有内存碎片
  • 相比于复制算法:有效利用堆

缺点

一次遍历活动对象+三次扫描整个堆,吞吐量较小。

小结

复制算法需要耗费的时间空间由什么决定?

存活对象的数量  和内存的总大小没关系

标记清除算法耗费的时间由什么决定?

内存的总大小,清除阶段需要遍历堆。

标记整理算法耗费的时间由什么决定?

1内存的总大小,整理阶段需要遍历三次堆。

2存活对象的数量

分代垃圾回收

分代收集理论建立在两个分代假说之上:

  • 弱分代假说:大多数对象都是朝生夕灭的。这个假说已经在不同的编程语言和编程范式中得到证实;
  • 强分代假说:越长寿的对象越不容易死亡。这个假说证据稍显不足,但是却依旧给大对象回收处理有一定的意义。

  这两个假说共同奠定了多款常用的垃圾收集器的一致设计原则:收集器应该将堆划分出不同区域,然后将回收对象依据年龄分配到不同的区域之中。

  除此之外新生代对象完全可以由老年代对象引用,如果产生这种引用,就需要遍历整个老年代来确定可达性分析的准确性,这样对内存回收带来极大的性能负担,所以引出了另一条假说

  • 跨代引用假说:跨代引用对比与同代引用来说仅占极少数

根据对象的存活周期的不同将内存划分为好几块。一般是把java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适合的收集算法。新生代中,每次垃圾收集时都发现大批对象死去,只有少量存活,那就选用复制算法。

新生代

复制算法

默认的,Edem : from : to = 8 : 1 : 1

为什么不需要上文说的同等大小的内存

1 大多数对象都是朝生夕灭

2老年代作担保当to Survivor区放不下直接晋升老年代

上图演示GC过程,黄色表示死对象,绿色表示剩余空间,红色表示幸存对象

新生代大小对于gc的影响

1消耗时间几乎不变。

2内存越小young gc越频繁,频繁也可能导致不会长期存活的对象进入老年代。

3如果Survivor空间小了,对象又多,且没被回收,空间又不够,那么就晋升老年代,这种堆的老年代会呈现持续增长的趋态。

大对象直接分配到老年代

1年轻带gc频率高,复制代价大

2Survivor 区有限可能导致别的对象晋升到老年代

老年代

标记清除 标记整理

老年代存储的对象比年轻代多得多,而且不乏大对象,对老年代进行内存清理时,如果使用停止-复制算法,则相当低效。一般,老年代用的算法是标记-清除算法,当碎片增多时在进行一次标记整理算法。

老年代大小对于gc的影响

1老年代越大一次gc时间越长需要遍历堆。

2老年代越大gc频率越低。

大内存将导致长暂停

跨代引用

  YGC时,为了找到年轻代中的存活对象,不得不遍历整个老年代;反之亦然。这种方案存在极大的性能浪费。因为跨代引用是极少的,为了找出那么一点点跨代引用,却得遍历整个老年代!

跨代引用带来的问题,采用CardTable很好的规避了遍历整个老年代的问题,HotSpot JVM的卡页(Card Page)大小为512字节,卡表(Card Table)被实现为一个简单的字节数组,即卡表的每个标记项为1个字节。

并发垃圾回收

GC线程与应用并发进行  cms g1

1 gc时需要预留空间给应用使用

2 并发模式可能失败回收速度赶不上应用的使用速度(concurrent mode failure),退化成full gc

将所有对象分为三种颜色

  • 白色:没有检查 或者是垃圾
  • 灰色:自身被检查了,成员没被检查完(可以认为访问到了,但是正在被检查,就是图的遍历里那些在队列中的节点)
  • 黑色:自身和成员都被检查完了

浮动垃圾

对象B是“应该”被回收的。然而因为B已经变为灰色了,其仍会被当作存活对象继续遍历下去。最终的结果是:这部分对象仍会被标记为存活,即本轮GC不会回收这部分内存

这部分本应该回收 但是 没有回收到的内存,被称之为“浮动垃圾”。浮动垃圾并不会影响应用程序的正确性,只是需要等到下一轮垃圾回收中才被清除。

另外,针对并发标记开始后的新对象,通常的做法是直接全部当成黑色,本轮不会进行清除。这部分对象期间可能会变为垃圾,这也算是浮动垃圾的一部分。

漏标

因为B已经没有对C的引用了,所以不会将C放到灰色集合;尽管因为A重新引用了C,但因为A已经是黑色了,不会再重新做遍历处理。
最终导致的结果是:C会一直停留在白色集合中,最后被当作垃圾进行清除。这直接影响到了应用程序的正确性,是不可接受的。

Incremental update 增量更新,关注引用的增加,如果发现黑色指向了白色,把黑色重新标记为灰色,remark过程将重新扫描属性。但是会造成重复扫描已扫描过的属性。(CMS对漏标的处理方式)

SATB snapshot at the beginning:关注引用的删除,当灰–>白消失时,要把这个 引用 推到GC的堆栈,保证白还能被GC扫描到。G1采用该方法。

一篇读懂jvm垃圾回收相关推荐

  1. 一文读懂Java 垃圾回收机制

    什么是自动垃圾回收? 自动垃圾回收是一种在堆内存中找出哪些对象在被使用,还有哪些对象没被使用,并且将后者删掉的机制. 所谓使用中的对象(已引用对象),指的是程序中有指针指向的对象:而未使用中的对象(未 ...

  2. 读懂 JVM 内存管理这篇就够了

    读懂 JVM 内存管理这篇就够了 JVM 的内存结构 程序计数器 作用 概述 PC寄存器的常见问题 虚拟机栈 栈中可能出现的异常 栈的存储单位 栈运行原理 栈帧的内部结构 局部变量表 槽 Slot 操 ...

  3. JVM垃圾回收机制(超级无敌认真好用,万字收藏篇!!!!)

    文章目录 JVM垃圾回收机制 1 判断对象是否存活的算法 1.1 引用计数器算法 1.2 可达性分析算法 2 对象的四种引用方式 2.1 强引用 2.2 软引用 2.3 弱引用 2.4 虚引用 3 垃 ...

  4. 【JAVA进阶】JVM第二篇- JVM 垃圾回收详解

    写在前面的话 脑子是个好东西,可惜的是一直没有搞懂脑子的内存删除机制是什么,所以啊,入行多年,零零散散的文章看了无数,却总是学习了很多也忘了很多. 痛定思痛的我决定从今天开始系统的梳理下知识架构,记录 ...

  5. 单例模式讨论篇:单例模式与垃圾回收

    出处:http://blog.csdn.net/zhengzhb/article/details/7331354   Jvm的垃圾回收机制到底会不会回收掉长时间不用的单例模式对象,这的确是一个比较有争 ...

  6. JVM 垃圾回收算法与ART CC回收器实现概述

    前言 在作者的上一篇文章<Android R常见GC类型与问题案例>中,对Demo应用的Heap堆结构与Space类型及相对应内存分配算法做了简要的探究,同时对Android R机器运行中 ...

  7. jvm - 垃圾回收 gc

    2019独角兽企业重金招聘Python工程师标准>>> jvm - 垃圾回收 注意 : 本系列文章为学习系列,部分内容会取自相关书籍或者网络资源,在文章中间和末尾处会有标注 垃圾回收 ...

  8. 11 JVM 垃圾回收(上)

    11 JVM 垃圾回收(上) 引用计数法和可达性分析 垃圾回收,就是将已经分配出去的,但却不在使用的内存回收回来,以便再次分配.在 Java 虚拟机语境下,垃圾指的是死亡的对象所占据的堆空间.下面就总 ...

  9. JVM内存区域(Java内存区域)、JVM垃圾回收机制(GC)初探

    一.JVM内存区域(Java内存区域) 首先区分一下JVM内存区域(Java内存区域)和Java内存模型(JMM)的概念.Java线程之间的通信采用的是共享内存模型,这里提到的共享内存模型指的就是Ja ...

  10. JVM架构、JVM垃圾回收机制、垃圾回收算法、垃圾回收器、JMM(内存模型)

    0 JVM和Java的关系 JDK = JRE + Java开发工具(java,javac,javadoc,javap-) JRE = JVM + Java核心类库 即: JDK = JVM + Ja ...

最新文章

  1. 如何动态的向数组中插入键值对_在Java中实现的一个简单“HashMap”
  2. C++中getline()和cin()同时使用时的注意事项
  3. 数据库知识点一共涉及这几方面知识
  4. STM32F1移植到STM32F407 (LD3320)
  5. Android UI个性style开源组件
  6. 用什么软件测试微信朋友圈被屏蔽,怎么检测朋友圈被屏蔽?清师傅帮你
  7. Python 数据处理数据挖掘(五):线性回归
  8. Siebel应用数据结构层次
  9. mockjs java_GitHub - mikove3y/mockj: 生成mock数据的利器,mockjs的java实现。同时内置随机 random 一个对象的功能...
  10. JavaScript中的静态函数
  11. dnf红眼补丁在哪下载_dnf红眼变红补丁下载
  12. 论文解读:Generated Knowledge Prompting for Commonsense Reasoning
  13. DM error code 达梦数据库-错误代码 汇总
  14. Android人脸检测方案汇总
  15. 营业执照识别api接口调用OCR识别
  16. 保姆级静态网站搭建-阿里云实践
  17. 19个极度冷门发大财职业
  18. 用C/C++实现网络监听抓包
  19. 虎奔教育二级c语言答案,【虎奔教育计算机二级C语言软件】虎奔教育计算机二级C语言下载 v6.3.4.0 最新版-趣致软件园...
  20. Linux下的磁盘克隆、磁盘备份、磁盘还原、分区克隆、分区备份、分区还原

热门文章

  1. bootable_noemulation.img linux,Syslinux使用
  2. VS2008 水晶报表部署
  3. 服务器的mysql目录在哪,oracle数据库目录在哪
  4. 算法—青蛙跳台阶问题汇总
  5. 霍普金斯计算机专业研究生如何,约翰·霍普金斯大学电气和计算机工程硕士研究生...
  6. 现在时间是 a 点 b 分,请问 t 分钟后,是几点几分?
  7. 使用igvtools可视化测序深度分布
  8. 闲鱼一直不确认收货怎么办?
  9. 网站怎么样对接微信公众号,看以下操作
  10. 基于vue+element的时间、农历、和日历的选择