本篇内容包括:JAVA 垃圾回收机制概述、有哪些内存需要回收、如何回收(标记-清除、标记-整理(标记-清除-压缩)、复制(标记-复制-清除)、分代收集等算法) 以及 何时进行垃圾回收等内容!

一、概述

Java 与 C++ 之间有一堵由内存动态分配和垃圾收集技术所围成的"高墙",墙外面的人想进去,墙里面的人却想出来

说起垃圾收集(Garbage Collection,下文简称GC),有不少人把这项技术当作Java语言的伴生产物。事实上,垃圾收集的历史远远比Java久远,在1960年诞生于麻省理工学院的Lisp是第一门开始使用内存动态分配和垃圾收集技术的语言。

当 Lisp 还在胚胎时期是,其作者 John McCarthy 就思考过垃圾收集器需要完成的三件事情:

  1. 有哪些内存需要回收?
  2. 什么时候回收?
  3. 如何回收?

二、有哪些内存需要回收?——对象已死?

在堆里面存放着 Java 世界中几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事情就是要确定这些对象之中哪些还“存活”着,哪些已经“死去”(即不可能再被任何途径 使用的对象)。

1、引用计数算法

引用计数是垃圾收集器中的早期策略。在这种方法中,堆中每个对象实例都有一个引用计数。当一个对象被创建时,就将该对象实例分配给一个变量,该变量计数设置为 1。当任何其它变量被赋值为这个对象的引用时,计数加 1(a = b,则b引用的对象实例的计数器+1),但当一个对象实例的某个引用超过了生命周期或者被设置为一个新值时,对象实例的引用计数器减 1。任何引用计数器为 0 的对象实例可以被当作垃圾收集。当一个对象实例被垃圾收集时,它引用的任何对象实例的引用计数器减 1。

优缺点:

  • 优点:引用计数收集器可以很快的执行,交织在程序运行中。对程序需要不被长时间打断的实时环境比较有利。

  • 缺点:无法检测出循环引用。如父对象有一个对子对象的引用,子对象反过来引用父对象。这样,他们的引用计数永远不可能为0。

2、可达性分析算法

可达性分析算法是从离散数学中的图论引入的,程序把所有的引用关系看作一张图,从一个节点 GC ROOT 开始,寻找对应的引用节点,找到这个节点以后,继续寻找这个节点的引用节点,当所有的引用节点寻找完毕之后,剩余的节点则被认为是没有被引用到的节点,即无用的节点,无用的节点将会被判定为是可回收的对象。

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

  • 栈帧中的局部变量表中的 reference 引用所引用的对象;
  • 方法区中 static 静态引用的对象;
  • 方法区中 final 常量引用的对象;
  • 本地方法栈中 JNI(Native方法)引用的对象;
  • Java 虚拟机内部的引用, 如基本数据类型对应的 Class 对象, 一些常驻的异常对象(比如 NullPointExcepiton、OutOfMemoryError) 等, 还有系统类加载器;
  • 所有被同步锁(synchronized关键字) 持有的对象;
  • 反映 Java 虚拟机内部情况的 JMXBean、 JVMTI 中注册的回调、 本地代码缓存等。

这个算法的基本思路就是通过一系列的称为 GC Roots 的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots 没有任何引用链相连(用图论的话来说,就是从GC Roots 到这个对象不可达)时,则证明此对象是不可用的。


三、如何回收?

在 JVM 中主要的垃圾收集算法有:标记-清除、标记-整理(标记-清除-压缩)、复制(标记-复制-清除)、分代收集等算法。这几种收集算法互相配合,针对不同的内存区域采取对应的收集算法实现(这里具体是由相应的垃圾收集器实现)。

垃圾回收涉及到大量的程序细节,而且各个平台的虚拟机操作内存的方式也不一样,但是他们进行垃圾回收的算法是通用的,所以这里我们也只介绍几种通用算法。

1、标记-清除算法

算法实现:分为标记-清除两个阶段,首先根据上面的根搜索算法标记出所有需要回收的对象,在标记完成后,然后在统一回收掉所有被标记的对象。

缺点:

  • 效率低:标记和清除这两个过程的效率都不高。
  • 容易产生内存碎片:因为内存的申请通常不是连续的,那么清除一些对象后,那么就会产生大量不连续的内存碎片,而碎片太多时,当有个大对象需要分配内存时,便会造成没有足够的连续内存分配而提前触发垃圾回收,甚至直接抛出 OutOfMemoryExecption。

2、复制算法

为了解决标记-清除算法的两个缺点,复制算法诞生了。

算法实现:将可用内存按容量划分为大小相等的两块区域,每次只使用其中一块,当这一块的内存用完了,就将还活着的对象复制到另一块区域上,然后再把已使用过的内存空间一次性清理掉。

优缺点:

  • 优点:每次都是只对其中一块内存进行回收,不用考虑内存碎片的问题,而且分配内存时,只需要移动堆顶指针,按顺序进行分配即可,简单高效。

  • 缺点:将内存分为两块,但是每次只能使用一块,也就是说,机器的一半内存是闲置的,这资源浪费有点严重。并且如果对象存活率较高,每次都需要复制大量的对象,效率也会变得很低。

3、标记-整理算法

上面我们说过复制算法会浪费一半的内存,并且对象存活率较高时,会有过多的复制操作,效率低下。如果对象存活率很高,基本上不会进行垃圾回收时,标记-整理算法诞生了。

算法实现:首先标记出所有存活的对象,然后让所有存活对象向一端进行移动,最后直接清理到端边界以外的内存。

局限性:只有对象存活率很高的情况下,使用该算法才会效率较高。

4、分代收集算法

当前商业虚拟机都是采用此算法,但是其实这不是什么新的算法,而是上面几种算法的合集。

算法实现:根据对象的存活周期不同将内存分为几块,然后不同的区域采用不同的回收算法。

对于 HotSpot 虚拟机,它将堆空间分为老年代和新生代两块区域

  • 对于存活周期较短,每次都有大批对象死亡,只有少量存活的区域,采用复制算法,因为只需要付出少量存活对象的复制成本即可完成收集;

  • 对于存活周期较长,没有额外空间进行分配担保的区域,采用标记-整理算法,或者标记-清除算法。

堆有新生代和老年代两块区域组成,而新生代区域又分为三个部分,分别是 Eden、From Surivor、To Survivor,比例是8:1:1。

新生代采用复制算法,每次使用一块 Eden 区和一块 Survivor 区,当进行垃圾回收时,将 Eden 和一块 Survivor 区域的所有存活对象复制到另一块 Survivor 区域,然后清理到刚存放对象的区域,依次循环。

老年代采用标记-清除或者标记-整理算法,根据使用的垃圾回收器来进行判断。

至于为什么要这样,这是由于内存分配的机制导致的,新生代存的基本上都是朝生夕死的对象,而老年代存放的都是存活率很高的对象。


四、何时进行垃圾回收

理清了什么是垃圾,怎么回收垃圾,最后一点就是Java虚拟机何时进行垃圾回收呢?

程序员可以调用 System.gc() 方法,手动回收,但是调用此方法表示希望进行一次垃圾回收。但是它不能保证垃圾回收一定会进行,而且具体什么时候进行是取决于具体的虚拟机的,不同的虚拟机有不同的对策。

其次虚拟机会自行根据当前内存大小,判断何时进行垃圾回收,比如前面所说的,新生代满了,新产生的对象无法分配内存时,便会触发垃圾回收机制。

这里需要说明的是宣告一个对象死亡,至少要经历两次标记,前面我们说过,如果对象与 GC Roots 不可达,那么此对象会被第一次标记并进行一次筛选,筛选的条件是此对象是否有必要执行 finalize() 方法,当对象没有覆盖 finalize() 方法,或者该方法已经执行了一次,那么虚拟机都将视为没有必要执行 finalize() 方法。

如果这个对象有必要执行 finalize() 方法,那么该对象将会被放置在一个有虚拟机自动建立、低优先级,名为 F-Queue 队列中,GC 会对 F-Queue进行第二次标记,如果对象在 finalize() 方法中成功拯救了自己(比如重新与GC Roots建立连接),那么第二次标记时,就会将该对象移除即将回收的集合,否则就会被回收。

深入理解Java虚拟机:Java垃圾回收机制相关推荐

  1. 深入理解Java虚拟机——JVM垃圾回收机制和垃圾收集器详解

    一:概述 说起垃圾回收(Garbage Collection,GC),很多人就会自然而然地把它和Java联系起来.在Java中,程序员不需要去关心内存动态分配和垃圾回收的问题,顾名思义,垃圾回收就是释 ...

  2. 浅析Java虚拟机的垃圾回收机制(GC)

    目录 一.垃圾回收机制(Garbage Collection) 二.对象回收的时机 引用计数法 可达性分析算法 三.垃圾回收算法 标记-清除算法 标记-复制算法 标记-整理算法 新生代.老年代.永久代 ...

  3. Java虚拟机:垃圾回收机制与垃圾收集器

    一.垃圾回收机制: 1.垃圾回收的过程: JVM内存区域的程序计算器,虚拟机栈.本地方法栈的生命周期是和线程同步的,随着线程的销毁而自动释放内存,所以只有堆和方法区需要GC,方法区主要是针对常量池的回 ...

  4. Java高级进阶学习资料!Java虚拟机的垃圾回收机制

    Maven权威指南 首先,本书适合所有Java程序员阅读.由于自动化构建.依赖管理等问题并不只存在于Java世界,因此非Java程序员也能够从该书中获益.无论你是从未接触过Maven.还是已经用了Ma ...

  5. 学习笔记【Java 虚拟机②】垃圾回收

    若文章内容或图片失效,请留言反馈.部分素材来自网络,若不小心影响到您的利益,请联系博主删除. 总目录 学习笔记[Java 虚拟机①]内存结构 学习笔记[Java 虚拟机②]垃圾回收 学习笔记[Java ...

  6. Java虚拟机之垃圾回收详解一

    Java虚拟机之垃圾回收详解一 Java技术和JVM(Java虚拟机) 一.Java技术概述: Java是一门编程语言,是一种计算平台,是SUN公司于1995年首次发布.它是Java程序的技术基础,这 ...

  7. 一篇文章搞定java中的垃圾回收机制面试题

    一篇文章搞定java中的垃圾回收机制面试题 任何语言在运行过程中都会创建对象,也就意味着需要在内存中为这些对象在内存中分配空间,在这些对象失去使用的意义的时候,需要释放掉这些内容,保证内存能够提供给新 ...

  8. java gc 有钱人_小猿圈java之GC垃圾回收机制

    垃圾回收机制是提高性能的重要机制,所以不管学什么语言也好,垃圾回收机制都是有的,也是很重要的,小猿圈这章详解一下java的GC垃圾回收机制,需要用的或者感兴趣的朋友们,可以跟着小编学习一下. 一.GC ...

  9. java虚拟机多久触发垃圾回收_每日一问:讲讲 Java 虚拟机的垃圾回收

    昨天我们用比较精简的文字讲了 Java 虚拟机结构,没看过的可以直接从这里查看: 每日一问:你了解 Java 虚拟机结构么? 今天我们必须来看看 Java 虚拟机的垃圾回收算法是怎样的.不过在开始之前 ...

  10. python垃圾回收机制原理_如何理解和掌握Python垃圾回收机制?

    在编程世界里,当一个对象失去引用或者离开作用域后,它就会被当做垃圾而被自动清除,这就是垃圾回收机制.在现在的高级语言如Python.Java都使用了垃圾回收机制,不过与Java采用的垃圾收集机制不同, ...

最新文章

  1. 计算机网络安全防护体系研究
  2. hibernate框架int和Integer类型区别
  3. php实现tcp连接esp8266,ESP8266之TCP透传
  4. recyclerview 滚动冲突_如何处理手势冲突 | 手势导航连载 (三)
  5. 【从零开始学BPM,Day2】默认表单开发
  6. snakebar 的使用
  7. 数据结构和算法分析:B树 B+树 和B*树的总结
  8. 计算机科学与技术科研论文,计算机科学与技术学院2007年度科研论文一览表
  9. 中山大学计算机专业研究生报录比,中山大学报录比(中山大学2019各专业报录比)...
  10. 拼多多回应“轩尼诗假酒”案:实际售出3单 9月已关闭店铺
  11. PHP-laravel框架一1
  12. ThoughtWorks 2018校招作业
  13. 模拟电路设计(23)---模数和数模转换器概述
  14. 如何给HTML文件加一张背景图,如何在css中添加背景图?
  15. 火柴棒游戏(暴力枚举)C++
  16. dubbo的可扩展机制SPI源码解析(二)
  17. Docker简介与安装
  18. 《疯狂Java讲义》第5章 面向对象(上)——课后练习
  19. 学习笔记-Python-DataFrame常见操作总结
  20. 涉密计算机系统分级保护,计算机信息系统分级保护方案.pdf

热门文章

  1. 技能学习:学习使用php(tp6框架) + vue.js,开发前端全栈网站-4.跨域且传输数据,并优化后端接口
  2. android 重力感应 讲解
  3. 程序切片(定义+用途)
  4. 终于,百度“地震”了!
  5. 蓝桥练习题(C++)——门派制作
  6. QQ名片赞点赞接口PHP源码
  7. 从拨号音分析拨号号码
  8. 红帽企业linux服务器版,红帽企业版的衍生系统_Microsoft SERVER 2012 简体中文标准版_服务器知识学堂-中关村在线...
  9. 移动硬盘数据恢复怎么操作?马上学会!
  10. 51nod1522上下序列