关于Java垃圾回收问题的总结

文章目录

  • 关于Java垃圾回收问题的总结
  • 前言
  • 1、垃圾
    • 1、什么是垃圾
    • 2、垃圾判断算法
      • 引用计数法
      • 可达性分析
      • 引用
  • 2、垃圾回收算法
  • 3、垃圾回收器

前言

Java语言的可移植性建立在JVM的基础上的,只要任何平台装有Java虚拟机,字节码文件,就可以在这个平台上运行,就这实现了“一次编译,多次运行”。作为Java语言最重要特性之一的自动垃圾回收机制,也是基于JVM实现的。那么他是怎么实现的呢?


1、垃圾

1、什么是垃圾

在Java中所有对象都是存放在堆中的,所以垃圾回收也是主要在堆中进行的。在JVM看来,垃圾是在堆中存在并且已经“死亡”的对象。那什么是“死亡”呢?我们可以简单地理解为不被任何途径使用的对象,那怎么样来判断对象的“死亡”呢?这就涉及到垃圾判别算法,主要有引用计数法和可达性分析。

2、垃圾判断算法

引用计数法

在这种算法中,给每个对象都设置一个引用计数器,当一个地方引用该对象时,引用计数器就+1;当引用失效时,引用计数器就-1;当引用计数器为0时,说明这个对象没有被任何对象引用,也就是垃圾,就可以被收集了。

· 优点:实现起来较为简单,对程序不被长时间打断有利。
· 缺点:需要额外的空间来储存计数器;无法解决循环引用问题,当A引用B,B也引用A的时候,此时A和B对象的引用都不为0,此时就无法进行垃圾回收。所以主流虚拟机都不采用此方法。

可达性分析

可达性分析也叫根搜索法,一个对象只有满足一下两个对象之一才会被成为可达的:
· 对象被一个可达对象引用
· 对象属于根集中的对象

在Java中,会将以下对象标记为根集对象:
· 虚拟机栈中引用的对象
· 方法区静态属性引用的对象
· 方法区常量池引用的对象
· 本地方法区JNI引用的对象
· 活跃的线程
根集的对象被称为GC Roots,从GC Roots开始向下搜索,搜索走过的路称为引用链,如果一个对象到GC Roots没有用任何引用链链接,那么这个对象就是不可达的。反之则为可达的。

· 优点:解决了循环引用问题,且不占用额外的空间
· 缺点:多线程场景下,其他线程可能会更新已经访问过的对象的引用


引用

在Java中有四种引用类型:
1、 强引用:比如 Object obj = new Object(),这类是Java中最常见的引用。只要引用还存在,就永远不会收集。
2、 软引用:它用来描述一些可能还有用,但并非必须的对象。在系统内存不够用时,这类引用关联的对象将被垃圾收集器回收。
3、 弱引用:它也是用来描述非必须对象的,但它的强度比软引用更弱些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。
4、 虚引用:也称为幻引用,最弱的一种引用关系,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的是希望能在这个对象被收集器回收时收到一个系统通知。

2、垃圾回收算法

标记清除法:第一步:利用可达性遍历内存,把存活对象和垃圾对象进行标记。
第二步:在遍历一遍,把垃圾对象回收掉。
特点:效率不太好,标记和清除的效率都不太高,标记和清除后会产生大量的不连续的空间分片,可能会导致之后程序运行需要分配较大的对象而找不到储存空间而在进行一次GC。

· 特点:效率不太好,标记和清除的效率都不太高,标记和清除后会产生大量的不连续的空间分片,可能会导致之后程序运行需要分配较大的对象而找不到储存空间而在进行一次GC。

标记整理法
第一步:利用可达性遍历内存,把存活对象和垃圾对象进行标记。
第二步:将所有存活对象向一端移动,把端边界以外的对象全部清除掉。

· 特点:适用于存货对象多,垃圾少的情况下,无空间碎片产生。

复制算法

将内存按照容量大小分为大小相等的两块,每次只使用一块,当一块使用完了,就把还存活着的对象转移到另一块,再把使用的内存清除。

· 特点:标记阶段和复制阶段可以同时进行;每次只对一块内存进行回收,运行高效,不会产生空间碎片,但是内存使用效率极低

分代收集
Java虚拟机一般将内存划分为新生代和老年代,在新生代中,有大量死去和少量存活对象,所以采用复制算法,因为只需要付出少量存活对象的复制成本就可以完成收集。老年代中存活对象占大多数,所以采用标记清除或整理法进行回收。

· 新生代:几乎所有新生成的对象都放在新生代中。新生代的内存按照8:1:1的比例分为Eden区和Survivor0区和Survivor1区;大部分对象放在Eden区但是当Eden区空间不足时,则会发起一次GC。回收时先将Eden区存活的对象放在Survivor0 区,然后清空Eden区,然后当Survivor0区也放满了,就把Eden区和Survivor0区存活的对象放在Survivor1区中,然后清空Eden区和Survivor0区,此时Survivor0区为空,交换Survivor0区和Survivor1区,保持Servivor1区为空。当Survivor1区不足以放下Eden区和Survivor0区存活的对象时,就会将存活的对象放进老年代里。当对象在Survivor躲过一次GC时,其年龄就会+1,默认情况下当年龄达到15岁时就会移动到老年代。如果老年代也存放满,就会触发一次Full GC,也就是新生代和老年代都会进行垃圾回收。
· 老年代:在新生代中经历了 N 次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。内存比新生代也大很多(大概比例是 1:2),当老年代内存满时触发 Full GC,Full GC 发生频率比较低,老年代对象存活时间比较长,存活率高。一般来说,大对象会被直接分配到老年代。所谓的大对象是指需要大量连续存储空间的对象,最常见的一种大对象就是大数组。当然分配的规则并不是百分之百固定的,这要取决于当前使用的是哪种垃圾收集器组合和 JVM 的相关参数。

3、垃圾回收器

垃圾回收(GC)线程与应用线程保持相对独立,当系统需要执行垃圾回收任务时,先停止工作线程,然后命令 GC 线程工作。以串行模式工作的收集器,称为Serial Collector,即串行收集器;与之相对的是以并行模式工作的收集器,称为Paraller Collector,即并行收集器。

Serial 收集器
串行收集器采用单线程方式进行收集,且在 GC 线程工作时,系统不允许应用线程打扰。此时,应用程序进入暂停状态,即 Stop-the-world。Stop-the-world 暂停时间的长短,是衡量一款收集器性能高低的重要指标。Serial 是针对新生代的垃圾回收器,采用“复制”算法。

ParNew 收集器
并行收集器充分利用了多处理器的优势,采用多个 GC 线程并行收集。可想而知,多条 GC 线程执行显然比只使用一条 GC 线程执行的效率更高。一般来说,与串行收集器相比,在多处理器环境下工作的并行收集器能够极大地缩短 Stop-the-world 时间。ParNew 是针对新生代的垃圾回收器,采用“复制”算法,可以看成是 Serial 的多线程版本

Parallel Scavenge 收集器
Parallel Scavenge 是针对新生代的垃圾回收器,采用“复制”算法,和 ParNew 类似,但更注重吞吐率。在 ParNew 的基础上演化而来的 Parallel Scanvenge 收集器被誉为“吞吐量优先”收集器。吞吐量就是 CPU 用于运行用户代码的时间与 CPU 总消耗时间的比值,即吞吐量 = 运行用户代码时间 /(运行用户代码时间 + 垃圾收集时间)。如虚拟机总运行了 100 分钟,其中垃圾收集花掉 1 分钟,那吞吐量就是99%。

Parallel Scanvenge 收集器在 ParNew 的基础上提供了一组参数,用于配置期望的收集时间或吞吐量,然后以此为目标进行收集。通过 VM 选项可以控制吞吐量的大致范围:

  • MaxGCPauseMills:期望收集时间上限,用来控制收集对应用程序停顿的影响。
  • GCTimeRatio:期望的 GC 时间占总时间的比例,用来控制吞吐量。
  • UseAdaptiveSizePolicy:自动分代大小调节策略。
    但要注意停顿时间与吞吐量这两个目标是相悖的,降低停顿时间的同时也会引起吞吐的降低。因此需要将目标控制在一个合理的范围中。

Serial Old 收集器
Serial Old 是 Serial 收集器的老年代版本,单线程收集器,采用“标记-整理”算法。这个收集器的主要意义也是在于给 Client 模式下的虚拟机使用。

Parallel Old 收集器
Parallel Old 是 Parallel Scanvenge 收集器的老年代版本,多线程收集器,采用“标记-整理”算法。

CMS收集器
CMS(Concurrent Mark Swee)收集器是一种以获取最短回收停顿时间为目标的收集器。CMS 收集器仅作用于老年代的收集,采用“标记-清除”算法,它的运作过程分为 4 个步骤:

初始标记(CMS initial mark)
并发标记(CMS concurrent mark)
重新标记(CMS remark)
并发清除(CMS concurrent sweep)
其中,初始标记、重新标记这两个步骤仍然需要 Stop-the-world。初始标记仅仅只是标记一下GC Roots能直接关联到的对象,速度很快,并发标记阶段就是进行GC Roots Tracing的过程,而重新标记阶段则是为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始阶段稍长一些,但远比并发标记的时间短。

CMS 以流水线方式拆分了收集周期,将耗时长的操作单元保持与应用线程并发执行。只将那些必需 STW 才能执行的操作单元单独拎出来,控制这些单元在恰当的时机运行,并能保证仅需短暂的时间就可以完成。这样,在整个收集周期内,只有两次短暂的暂停(初始标记和重新标记),达到了近似并发的目的。

CMS收集器优点:并发收集,低停顿。
CMS收集器缺点

  • CMS 收集器对 CPU 资源非常敏感;
  • CMS 收集器无法处理浮动垃圾;
  • CMS 收集器是基于“标记-清除”算法,该算法的缺点都有。
  • CMS 收集器之所以能够做到并发,根本原因在于采用基于“标记-清除”的算法并对算法过程进行了细粒度的分解。前面已经介绍过“标记-清除”算法将产生大量的内存碎片这对新生代来说是难以接受的,因此新生代的收集器并未提供 CMS 版本。
    G1收集器
    采用标记整理算法实现,运作过程:初始标记,并发标记,最终标记,筛选回收。不会产生大量空间碎片,可以精确控制停顿;G1将整个堆分为大小相等的多个Region ,G1跟踪每个区域的垃圾大小,在后台维护一个优先级列表,每次根据允许的收集时间,优先回收价值最大的区域,以达到在有限的时间获得最高的回收效率。
    G1的GC模式分为两种:
    · Yong GC:就是在新生代中 ,当所有 Eden 区域使用达到最大阀值并且无法申请足够内存时,会触发一次 YoungGC。每次 Young GC 会回收所有 Eden 以及 Survivor0 区的垃圾,并将存活对象复制到Survivor1区和Old区。
    · Mix GC:这里引入Rset概念,什么是Rset呢?Rset是Region的一小部分区域,用于记录其他Region引用当前Region的记录。首先会进行初次标识,仅仅标记一下GC Roots 和RootRegion需要STW。第二步,会扫描整个Old区,看Old区的Region中的Rset是否被RootRegion引用,如果被引用就会对该Region进行标记;第三步,并发标记因为只需要遍历没有被Root Region标记的区域,所以范围缩小了;第四步重新标记,是为了修正并发标记期间因用户程序继续运作而导致标记产生变动的那一部分对象的标记记录,但是G1不同于CMS采用了SATB速度是比CMS快的;第五步清理,采用了复制清理所以会STW。但是智慧选择垃圾量较多的Region进行清理,而不是全部清理,虽然垃圾清理不太干净,但是清理的时间会非常的短。

关于Java垃圾回收问题的总结相关推荐

  1. 假期三天,我肝了万字的Java垃圾回收,看完你还敢说不会?

    大家好,我是狂聊,上一篇已经把 Jvm 的运行区数据和类加载机制聊完了. 今天来说说 Java 垃圾回收,高频面试问题. 提纲附上,话不多说,直接干货 1.什么是垃圾回收? 垃圾回收(Garbage ...

  2. java垃圾回收机制_笔记 | Java垃圾回收机制

    本文经授权转载自程序员杂货铺(ID:speakFramework) 垃圾回收 最近上海的小伙伴是不是要被强垃圾分类搞疯了???哈哈哈哈 上海是个走在前列的城市啊,不光骑自行车闯红灯要被罚钱,垃圾不分类 ...

  3. 细述 Java垃圾回收机制→Types of Java Garbage Collectors

    本文将会介绍各种不同类型的Java垃圾回收器.垃圾回收是Java用来将程序员从分配和释放内存的琐事中解放出来的自动过程. Java有四种类型的垃圾回收器, Serial Garbage Collect ...

  4. 细述 Java垃圾回收机制→Java Garbage Collection Monitoring and Analysis

    本文非原创,翻译自Java Garbage Collection Monitoring and Analysis 在Java中为对象分配和释放内存空间都是由垃圾回收线程自动执行完成的.和C语言不一样的 ...

  5. Java垃圾回收工作原理

    在C++中,在heap上分配对象比在stack上分配对象更加昂贵.程序需要找到合适的内存块,再返回内存的地址.但是在Java中垃圾回收器显著地提高了在heap上分配对象的速度.听起来会有些怪,但是这就 ...

  6. Java 垃圾回收机 GC Roots详解(Garbage Collection Roots)

    背景: 之前面试阿里支付宝,被问到常见的GC Root 是什么? 当时自己支支吾吾,明明自己看过深入理解Java 虚拟机这本书,但是就是回答不上来. 后来自己工作中,遇到内存泄漏问题.我百度,下载了M ...

  7. Java垃圾回收机制(Garbage Collection)

    引用博客地址:http://www.cnblogs.com/ywl925/p/3925637.html 以下两篇博客综合描述Java垃圾回收机制 第一篇:说的比较多,但是不详细 http://www. ...

  8. java垃圾回收机制串行_Java垃圾回收机制

    Java语言是一门自动内存管理的语言,不再需要的对象可以通过垃圾回收自动进行内存释放. Java运行时内存区域划分 JVM将Java程序运行时内存区域划分成以下几个部分: 程序计数器(Program ...

  9. java垃圾回收机制_JVM的垃圾回收机制——垃圾回收算法

    一.Java垃圾回收机制 在java中,程序员是不需要显示的去释放一个对象的内存的,而是由虚拟机自行执行.在JVM中,有一个垃圾回收线程,它是低优先级的,在正常情况下是不会执行的,只有在虚拟机空闲或者 ...

  10. java垃圾回收根对象_Java垃圾回收怎么理解?

    展开全部 Java的堆是一个运行时数据区,类的实例(对象)从中62616964757a686964616fe58685e5aeb931333339653664分配空间.Java虚拟机(JVM)的堆中储 ...

最新文章

  1. C语言数据类型所占空间大小
  2. 1行代码消除PyTorch的CUDA内存溢出报错,这个GitHub项目刚发布就揽星600+
  3. 导师:CV学的这么差,你别毕业了
  4. 图像语义分割之FCN和CRF
  5. Windows 10将为大型企业提供订阅型服务
  6. react-native-sound的使用
  7. 涂鸦WIFI模组方案(模组 SDK)
  8. [UE4]响应鼠标点击
  9. 电商独立站-谷歌SEO指标
  10. 前轮转向最大角度设计原来_转向系统的工作原理
  11. tpx色卡电子版_潘通色卡电子版Pantone TPX(新175色)
  12. java案例4-5图形的面积与周长计算程序
  13. 用python证明采样定理_这一切都从指数函数开始(4)——采样定理
  14. 零基础个人网站搭建教程(一个完全的新人如何搭建自己的个人网站)
  15. 大文本文件打开工具_信息技术类专业常用工具软件教案1.1
  16. hiveSQL面试题16__时间序列--构造日期
  17. Tolua for Unity3d 编译字节码
  18. C++ define用法
  19. 基于 YOLOV3的交通车辆检测
  20. SAP MM 进销存报表与标准报表MB5B

热门文章

  1. SecureCRT快速连接服务器
  2. 谷歌浏览器CSND广告屏蔽方法
  3. android手机小内存,世界最小Android手机问世 仅2.4英寸512MB内存
  4. 无皇刀谭 · 异邦人
  5. java/php/net/python养花助手平台设计
  6. sentinel1 SNAP水体提取
  7. 站住!我要送你点网格智能干货
  8. Material Theme on sublime text 3 一个用起来很好的Sublime主题
  9. 推荐一款MySQL开源客户端,免费+跨平台+使用便捷
  10. 【设计模式】之抽象工厂模式