摘要:

垃圾回收这一步对于jvm十分重要,内存管理虽然不用手动管理,但是对于查错确实,排错确是十分重要哦!

大致流程:允许GC之后(注意,发动GC也是需要一定的要求步骤,不详细展开,会另写博客进行说明)-> 开始查找那些允许被回收的(两个算法)-> 开始回收(四个算法)

上述是简单的流程,根据不同的垃圾回收器,用到的思想大致如此,具体实现步骤不同。

有请提示:垃圾回收器是可以用到好几个算法,组合起来更强大。然后jvm进行GC的时候,也是将垃圾回收器进行组合的。

第一步:那些对象是垃圾:

1,引用计数法:通过对引用的遍历,找到对应的实例,让对应的实例计数加  1 ,如果引用取消,或者指向null,实例的引用减  1 。把找到的引用都遍历一遍之后,如果发现有对象实例的计数是0。那么这个对象 就是垃圾对象了。在通过垃圾回收算法对其进行 回收即可。

缺点:想想一下,有两个类,互相引用,也就是A对象的实例(也就是对象的全局变量)是一个指向B对象的引用,B对象实例是一个指向A对象的引用。那么这两个对象的引用计数,永远不可能是0 。也就不可能对其进行回收了。

2,可达性分析法:这个算法类似于树的遍历,学过数据结构的小伙伴应该会好理解。简单来说,按照一定的规则说明那些可以作为一个根节点(GC root),然后以这些根节点去访问其引用的对象,被访问的对象又会有其他对象的引用。想象一下,是不是像极了树的遍历。这个路径称作引用链,但凡是在引用链上的对象,都是可用的。注意,引用连的起始点都是GC root 哦。虽然有其他对象存在类似于引用链的结构,但是,起始点不是GC root的那一些,都是垃圾,可以被回收的。

GC root的查找规则:java栈中的引用,方法区中的静态属性(静态变量 + 静态常量),方法区中常量引用的对象(方法区中有个结构 叫做 常量池 ,存储的一部分是常量),本地方法(线程独占区中有个结构叫做 本地方法栈)。

一般情况下,都是使用的 可达性分析法去查找垃圾类实例。

第二步:垃圾回收器算法(标记-清除、复制算法、标记-整理、分代算法)

1,标记-清除:找到垃圾类之后,标记一下。然后直接 清除即可。(算法很快)

缺点:产生空间碎片,不利于大对象的安排进去。

2,复制算法:将内存分为四块:新生代(Eden),生存代(Survivor * 2),老年代。有五种内存分配策略,讲完之后再说。类的升级流程是Eden->Survivor->老年代;

算法流程:1),先找到垃圾类,将可以使用的类移动到Survivor2,将Eden + 另一块Survivor1中的内存全部清除。

2),将新生成的类实例优先分配到Eden,分配不下时,放到Survivor2。进行GC时,将Survivor2中对象的满足一定条件(例如对象年龄达到某一个标准)的对象分配到老年代中。将本次GC存活下来的分配到Survivor1中,在清除Eden + Survivor2 。依次循环即可。

缺点:很容易发现吧,Survivor中每次都会浪费一个Survivor的内存没有使用,所以为了减少浪费,一半将Eden的内存扩大,Survivor的内存设置小一点。例如:HotSpot(HotSpot是8中的jvm默认虚拟机) 中设置的是 8 : 1 : 1;

3,标记-整理:看名字是不是感觉很熟悉,没错。跟标记-清除很像,也是直接标记。改算法使用到了前面两个算法的精华,改善了缺点。

算法流程:1),直接标记

2),集中,无缝隙的移动到一端,此时会发现,剩下的垃圾类,都会在其他地方。移动完成之后就会发现有一个边界,就是可用类跟其他空间的一个边界,下一步直接把边界以外的空间直接清除掉就可以了。

缺点:看起来很完美,但是越完美的,往往在时间上过不去。

4,分代算法:根据在哪里清除,选用算法不一样。

算法流程:1),新生代采用复制算法

2),老年代采用标记-清除算法(老年代GC很少访问,类也很少去直接分配到里面,内存碎片的可怕性就显得不那么重要了)

下面说说内存分配原则:

1,对象优先分配到Eden区域;

2,大对象直接分配到老年区:大对象的就是,对象里面有很大数组或者很大的字符串;

3,长时间存活的对象存入老年区:就是上面复制算法里面说的那个对象升级流程;

4,动态对象年龄判定:jvm并不是永远地要求对象的年龄必须达到了MaxTenuringThreshold才可以进入老年代,如果Survivor空间中年龄相同的所有对象的总空间>=本servivor中的一半,那么年龄>=本年龄的对象可以直接进入老年区;

5,空间分配原则:简单来说,就是在发生Minor GC(在新生代进行GC)情况下,为了防止发生在Minor GC后,Eden有大量存活的对象,导致survivor不能全部存入,这时需要老年代去担保,把这些对象放入老年代,但是要确保老年要存的下。

1),再发生Minor GC之前,检查老年区的可用的连续空间是否是大于新生代(Eden)的所有对象的总空间,如果是,直接全部晋升老年代,保证Minor GC的安全;

2),如果不行,就检查HandlePromotionFailure(可以手工设定)参数时候允许担保失败,允许的话,直接分配。不能的话,发生一次full GC(或者是Major GC   在老年代进行GC)。

3),不允许担保失败,发生一次 full GC。

为什么不直接进行full GC ,因为速度慢呀。而且经常GC 也 效果不大,因为老年代都是一些长期存活的对象。

最后一个模块:垃圾回收器,主要有七种。说一下工作流程跟特点。注意哦,jvm可以根据不同的场景,使用不同的垃圾回收器。例如:如果要对老年代进行回收的话,可以选择

收集器有:Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS、G1(G1是目前最好的收集器)。

上图是HotSpot的垃圾收集器的使用范围,HotSpot是现在主流的 jvm。

1,Serial收集器 跟 Serial Old收集器:

这个两个收集器看名字就知道,Serial是针对于新生代的,Serial Old是针对老年代的。是最古老的垃圾收集器。

工作原理:要进行垃圾回收(GC)的时候,首先会进行StopTheWorld(意思是将目前所有的线程都停止掉),Serial 采用复制算法进行 单线程 处理,Serial Old采用标记-整理算法 对老年代进行 单线程处理。

优势:虽然是最古老的垃圾收集器,但是会简单高效,对于单cpu的,收集效率会很高,因为没有线程之间切换带来的时间消耗。可以用在Client(客户端),桌面应用上。

2,ParNew收集器:

ParNew收集器其实就是Serial收集器的多线程版本。但是,它确实目前server模式下虚拟机首选的垃圾收集器,原因后说。

工作原理:就是在StopTheWorld之后使用多线程进行回收垃圾。使用算法是复制算法。

优势:为什么会是首选的垃圾回收器,最主要的原因是因为CMS,CMS是个跨时代的收集器,真正意义上实现了并发收集垃圾,也就是说,妈妈在收拾房间的时候, 你还可以丢垃圾,而Serial、ParNew、Parallel都是你的乖乖待在一个地方,直到妈妈把房间打扫好之后才可以继续制造。为什么还需要ParNew呢?因为CMS是针对老年代进行回收的,还缺一个对新生代回收的,而新生代回收的垃圾回收器有三个:Serial、ParNew、Parallel。Parallel性能肯定比ParNew性能好,为什么不使用呢?因为在JDK1.4.0中的存在的Parallel不能跟CMS一起配合使用,那能配合使用的只有Serial跟ParNew了,而现在服务器都是多核CPU,所以ParNew就成了虚拟机优先使用的垃圾收集器了。

3,Parallel收集器:

Parallel 收集器是一个新生代收集器,注重的是收集器的吞吐量(Parallel收集器也被称作是“吞吐量优先”收集器)

工作原理:跟ParNew收集器工作原理相似,只不过是严格控制了吞吐量(吞吐量就是CPU执行用户代码的时间比上CPU总消耗时间的比值,既(运行用户代码时间/(运行用户代码时间 + GC回收时间)))

优势:严格控制吞吐量,用户体验会更好,因为卡顿会更少。ParNew需要自己去设置参数,在Parallel中有一个参数

-XX:+UserAdaptiveSizePolicy

开关参数,开启后,不需要手工指定新生代大小、Eden 跟 Servivor比例,晋升老年代对象大小参数的细节参数,jvm会根据系统的运行情况收集性能监控信息,动态调整这些参数,这些操作称为GC自适应调节策略。对于新生会很友好。

这个也是Parallel跟ParNew的最主要的区别。

4,Parallel Old收集器:

产生原因:比较有意思,因为Parallel的地位很尴尬,因为Parallel是适用于新生代,那老年代有谁呢,一个是CMS,一个是Serial Old。但是CMS不能跟Parallel配合使用,但是Serial Old(在多核CPU中)会拖后腿。于是,本收集器产生了。终于Paralle 有了自己的组合搭档(Parallel + Parallel Old)

工作原理:多线程 + 标记-整理算法。其他流程跟Parallel、ParNew、Serial一样。

优势:在注意吞吐量以及CPU资源敏感的场合,都可以优先考虑使用Parallel + Parallel Old组合。

5,CMS收集器

他来了,他来了。

CMS收集器是一种以获取最短回收停顿时间为目标的收集器。

工作原理:基于标记-清除算法实现的,流程分为4步:

1),初始标记(仅仅标记一下GC Root,)

2),并发标记(是一个单独的线程,一起跟用户的线程一起 运行)

3),重新标记(去标记一下在运行期间发生变化的对象)

4),并发清除(是一个单独的线程,一起跟用户的线程一起 运行)

其中,初始标记跟重新标记任然需要Stop The World。

图中的安全点,跟发动GC有关,任何一个GC收集器动作都会设计安全点。另附博客说明。

6,G1收集器:

目前最强收集器,强到什么地步。不需要其他收集器配合,自己就可以管理新生代跟老年代。G1是面向服务端应用的垃圾收集器,HotSpot开发团队称在未来可以替换掉JDK1.5中发布的CMS收集器。

工作流程:算法:整体采用了标记-整理算法,局部使用了复制算法。工作流程也是分为4步:

1),初始标记

2),并发标记

3),最终标记

4),筛选回收

跟CMS的工作流程差不多。因为G1还正在开发优化,在大数据上应用停顿时间以及吞吐量还有缺陷。还没有大方面的普及。

本博客还差一点CMS跟G1的优缺点介绍,这方面内容颇多,已经干到晚上了,见谅。

垃圾回收(GC)流程相关推荐

  1. 垃圾回收(GC)浅谈

    关于内存 计算机通过两个机制,去实现内存的高效使用. 第一种机制是虚拟内存.硬盘的容量其实是远远大于内存的(RAM),虚拟内存会在内存不足的时候,把不经常访问的内存的数据写到硬盘里.虽然说硬盘容量比较 ...

  2. 垃圾回收机制?垃圾回收的流程?

    垃圾回收机制? Java中,一个显著地特点是引入了垃圾回收机制,编写程序时,不再需要考虑内存管理,有效的防止内存泄露,提高内存的内存率. 垃圾回收器通常作为一个单独的低级线程运行,不可预知的情况下,对 ...

  3. 【转】深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第六节 理解垃圾回收GC,提搞程序性能****

    前言 虽然在.Net Framework 中我们不必考虑内在管理和垃圾回收(GC),但是为了优化应用程序性能我们始终需要了解内存管理和垃圾回收(GC).另外,了解内存管理可以帮助我们理解在每一个程序中 ...

  4. python进阶19垃圾回收GC

    原创博客链接:python进阶19垃圾回收GC 垃圾收集三大手段 一.引用计数(计数器) Python垃圾回收主要以引用计数为主,分代回收为辅.引用计数法的原理是每个对象维护一个ob_ref,用来记录 ...

  5. python垃圾回收离职_垃圾回收gc.md

    垃圾回收gc python的垃圾收回机制不想c和c++是开发者自己管理维护内存的,python的垃圾回收是系统自己处理的,所以作为普通的开发者,我们不需要关注垃圾回收部分的内容,如果想要深层次理解py ...

  6. 垃圾回收GC经典算法

    目录 垃圾回收GC(Garbage Collection) 1.什么是垃圾 2.为什么要有GC 经典的GC算法 1.基本的一些概念 2.标记清除算法(Mark and Sweep) 3.复制法(cop ...

  7. IBM JDK(J9)垃圾回收(GC)策略

    在IBM JDK 1.5之后,采用了如下的垃圾回收GC策略: 针对吞吐量进行优化 -Xgcpolicy:optthruput(可选) 默认策略.对于吞吐量比短暂的 GC 停顿更重要的应用程序,通常使用 ...

  8. .net C# 堆 栈 垃圾回收 GC

    .NET C# .NET C# .NET C# .NET C# .NET C# .NET C# .NET C# 栈 堆 垃圾回收 GC #1 尽管在.NET framework下我们并不需要担心内存管 ...

  9. 第十五章: 菱悦 -垃圾回收GC详解

    第 15章 垃圾回收GC详解 文章目录 第 15章 垃圾回收GC详解 1.System.gc() 的理解 1.1.System.gc() 方法 1.2.不可达对象回收行为 2.内存溢出与内存泄漏 2. ...

  10. java using idispose_c# 垃圾回收(GC)优化

    GC,Garbage Collect,中文意思就是垃圾回收,指的是系统中的内存的分配和回收管理.其对系统性能的影响是不可小觑的.今天就来说一下关于GC优化的东西,这里并不着重说概念和理论,主要说一些实 ...

最新文章

  1. 为什么有些画面让你终生难忘?GAN来告诉你原因
  2. const常量和readonly常量区别
  3. Unity开发者如何有效地进行本土化
  4. spring+mybatis实现读写分离
  5. tim怎么设置检测到新版本自动安装 tim安全自动更新的开启方法
  6. 学习Spring Boot:(二十四)多数据源配置与使用
  7. 【IE】IE对line-height 失效的的解决方案
  8. 我常用的15 款开发工具!
  9. 沙箱环境和测试环境区别_带你一图了解iOS应用内购买流程,掌握测试环境搭建与测试方法...
  10. 内存一致性模型(Memory Consistency Models)
  11. RFID(Radio Frequency Identification)技术,又称无线射频识别
  12. 树莓派网易云音乐播放器
  13. ubuntu 键盘输入法为空_Ubuntu12下键盘输入中文设置 - 卡饭网
  14. 句法结构解析和Transition_based方法
  15. 图片验证码的逻辑实现
  16. html表格只设外边框,只设内边框
  17. 云时代编程语言Ballerina发布,TIOBE9月排行榜PHP排名在边缘飘摇(2019/09/16)
  18. 不可不知的安卓屏幕知识
  19. Java 将txt文本文档转换为excel
  20. java程序是怎么执行的

热门文章

  1. visudo退出保存
  2. plupload php实例,thinkPHP5框架整合plupload实现图片批量上传
  3. java 案例 吃货联盟
  4. wxml报错原因_微信小程序开发教程(八)视图层——.wxml详解
  5. SSM足球运动员训练计划管理系统的设计与实现 毕业设计-附源码281444
  6. 【Cocos Creator游戏开发教程】仿微信趣味画赛车小游戏(一)前言,界面UI
  7. OS——文件管理系统磁盘的结构之搞清盘面和柱面
  8. google chrome浏览器 模拟手机、浏览器访问手机网页
  9. 工作日志(显示器键盘鼠标打印机共享器故障)
  10. python导入xlrd_无法导入xlrd modu