什么是Java垃圾回收器

Java垃圾回收器是Java虚拟机(JVM)的三个重要模块(另外两个是解释器和多线程机制)之一,为应用程序提供内存的自动分配(Memory Allocation)、自动回收(Garbage Collect)功能,这两个操作都发生在Java堆上(一段内存快)。某一个时点,一个对象如果有一个以上的引用(Rreference)指向它,那么该对象就为活着的(Live),否则死亡(Dead),视为垃圾,可被垃圾回收器回收再利用。垃圾回收操作需要消耗CPU、线程、时间等资源,所以容易理解的是垃圾回收操作不是实时的发生(对象死亡马上释放),当内存消耗完或者是达到某一个指标(Threshold,使用内存占总内存的比列,比如0.75)时,触发垃圾回收操作。有一个对象死亡的例外,java.lang.Thread类型的对象即使没有引用,只要线程还在运行,就不会被回收。

回收的机制

依据统计分析可知,Java(包括一些其它高级语言)里面大多数对象生命周期都是短暂的,所以把Java内存分代管理。分代的目的无非就是为不同代的内存块运用不同的管理策略(算法),从而最大化性能。相对于年老代,通常年轻代要小很多,回收的频率高,速度快。年老代则回收频率低,耗时长。内存在年轻代里面分配,年轻代里面的对象经过多个回收周期依然存活的会自动晋升到年老代。

设计选型(Design Choices)

设计选型影响JVM垃圾回收器的实现难度,以及JVM的性能指标,适用于不同的场景。描述的是回收算法的风格特点。

单线程串行回收 VS 多线程并行回收

回收操作自身是否多线程处理的问题。单线程回收的优点是简单,易实现,碎片少,适用于单核的机器。多线程并行回收在多核机器上面可以充分的利用CPU资源,减少回收的时间,增加生产力,缺点是复杂且可能有部分碎片没有回收。

回收时暂停应用线程 VS 回收和应用并发进行

回收操作时是否暂停应用线程的问题。暂停应用线程的优点是简单、准确、清理得比较干净、清理的时间也短(CPU资源独占),缺点是暂停应用线程之后会造成垃圾回收周期内应用的回应时间拉长,实时性非常高的系统比较敏感。回收和应用线程并行处理的优点是应用反应时间比较平稳、缺点是实现难度大、清理频率高、可能有碎片。

不合并释放的内存片段 VS 合并释放的内存片段 VS 把活着的复制到新的地方

这三个选型描述的是如何管理死亡的内存块片段。死亡的内存片段通常散落在堆的各个地方,如果不加以管理会有两个问题,内存分配的时候因查找可用的内存而导致速度慢,小的碎片会导致内存的浪费(比如大的数组要求大的连续内存片段)。管理有两种方式,把活着的内存挪到内存块的某一端,记录可用内存的开始位置,或者干脆把活着的内存复制到一个新的内存区域,原来的内存块整个空出来。

性能指标(Performance Metrics)
  • 生产率(Throughput)
    一个较长的周期(长的周期才有意义)内,非回收时间占总时间的比率。度量系统的运行效率。
  • 垃圾回收花费(Garbage Collection overhead)
    一个较长的周期内,回收时间占总时间的比率。与生产率相对应,加起来为100%。
  • 暂停时间间隔(Pause time)
    Java虚拟机在回收垃圾的时候,有的算法会暂停所有应用线程的执行,某些系统可能对暂停的时间间隔比较敏感。
  • 回收的频率(Frequency of collection)
    平均多久会发生回收操作。
  • 内存占用的大小(Footprint)
    如堆的大小。
  • 实时性(Promptness)
    自一个对象死亡起,经过多久该对象所占用内存被回收。

垃圾回收的类型

所有的回收器类型都是基于分代技术。Java HotSpot虚拟机包含三代,年轻代(Young Generation)、年老代(Old Generation)、永久代(Permanent Generation)。

  • 永久代
    存储类、方法以及它们的描述信息。可以通过-XX:PermSize=64m-XX:MaxPermSize=128m两个可选项指定初始大小和最大值。通常 我们不需要调节该参数,默认的永久代大小足够了,不过如果加载的类非常多,不够用了,调节最大值即可。
  • 年老代
    主要存储年轻代中经过多个回收周期仍然存活从而升级的对象,当然对于一些大的内存分配,可能也直接分配到永久代(一个极端的例子是年轻代根本就存不下)。
  • 年轻代
    绝大多数的内存分配回收动作都发生在年轻代。比如,年轻代被划分为三个区域,原始区(Eden)和两个小的存活区(Survivor),两个存活区按功能分为From和To。绝大多数的对象都在原始区分配,超过一个垃圾回收操作仍然存活的对象放到存活区。

串行回收器(Serial Collector)

单线程执行回收操作,回收期间暂停所有应用线程的执行,client模式下的默认回收器,通过-XX:+UseSerialGC命令行可选项强制指定。

  • 年轻代的回收算法(Minor Collection)
    把Eden区的存活对象移到To区,To区装不下直接移到年老代,把From区的移到To区,To区装不下直接移到年老代,From区里面年龄很大的升级到年老代。 回收结束之后,Eden和From区都为空,此时把From和To的功能互换,From变To,To变From,每一轮回收之前To都是空的。设计的选型为复制。
  • 年老代的回收算法(Full Collection)
    年老代的回收分为三个步骤,标记(Mark)、清除(Sweep)、合并(Compact)。标记阶段把所有存活的对象标记出来,清除阶段释放所有死亡的对象,合并阶段 把所有活着的对象合并到年老代的前部分,把空闲的片段都留到后面。设计的选型为合并,减少内存的碎片。

并行回收器(Parallel Collector)

使用多个线程同时进行垃圾回收,多核环境里面可以充分的利用CPU资源,减少回收时间,增加JVM生产率,Server模式下的默认回收器。与串行回收器相同,回收期间暂停所有应用线程的执行。通过-XX:+UseParallelGC命令行可选项强制指定。

  • 年轻代的回收算法(Minor Collection)
    使用多个线程回收垃圾,每一个线程的算法与串行回收器相同。
  • 年老代的回收算法(Full Collection)
    年老代依然是单线程的,与串行回收器相同。

并行合并收集器(Parallel Compacting Collection)

年轻代和年老代的回收都是用多线程处理。通过命令可选项-XX:+UseParallelOldGC指定,–XX:ParallelGCThreads=3还可进一步指定参与并行回收的线程数。与串行回收器相同,回收期间暂停所有应用线程的执行。与并行回收器相比,年老代的回收时间更短,从而减少了暂停时间间隔(Pause time)。通过–XX:+UseParallelOldGC命令行可选项强制指定。

  • 年轻代的回收算法(Minor Collection)
    与并行回收器(Parallel Collector)相同
  • 年老代的回收算法(Full Collection)
    年老代分为三个步骤,标记、统计、合并。这里用到分的思想,把年老代划分为很多个固定大小的区(region)。 标记阶段,把所有存活的对象划分为N组(应该与回收线程数相同),每一个线程独立的负责自己那一组,标记存活对象的位置以及 所在区(Region)的存活率信息,标记为并行的。统计阶段,统计每一个区(Region)的存活率,原则上靠前面的存活率较高,从前到后, 找到值得合并的开始位置(绝大多数对象都存活的区不值得合并),统计阶段是串行的(单线程)。合并阶段,依据统计阶段的信息,多线程 并行的把存活的对象从一个区(Region)复制到另外一个区(Region)。

并发标记清除回收器(Concurrent Mark-Sweep Collector)

又名低延时收集器(Low-latency Collector),通过各种手段使得应用程序被挂起的时间最短。基本与应用程序并发地执行回收操作,没有合并和复制操作。通过命令行-XX:+UseConcMarkSweepGC指定,在单核或者双核系统里面还可以指定使用增量式回收模式-XX:+UseConcMarkSweepGC。增量式回收是指把回收操作分为多个片段,执行一个片段之后释放CPU资源给应用程序,未来的某个时点接着上次的结果继续回收下去。目的也是减少延时。

  • 年轻代的回收算法(Minor Collection)
    与并行回收器(Parallel Collector)相同
  • 年老代的回收算法(Full Collection)
    分为四个步骤,初始标记(Initial Mark)、并发标记(Concurrent Mark)、再次标记(Remark)、以及并发清理(Concurrent Sweep)。特别注意,没有合并操作,所以会有碎片。
  • 初始化阶段: 暂停应用线程,找出所有存活的对象,耗时比较短,回收器使用单线程。
  • 并发标记阶段: 回收器标记操作与应用并发运行,回收器使用单线程标记存活对象。
  • 再次标记:并发标记阶段由于应用程序也在运行,这个过程中可能新增或者修改对象。所以再次暂停应用线程,找出所有修改的对象,使用多线程标记。
  • 并发清理:回收器清理操作与应用并发运行,回收器使用单线程清理死亡对象。

Java垃圾回收器的性能评估工具

  • –XX:+PrintGCDetails–XX:+PrintGCTimeStamps
    垃圾回收的开始时间,持续时间,每一代的空余内存等信息。
  • jmap [options] pid
    jamp 2043 查看2043进程里面已经加载的共享对象。通常DLL文件。
    jmap -heap 2043 查看内存堆的配置信息以及使用情况。
    jmap -permstat 2043 查看永久代的加载情况。
    jmap -histo 2043 查看类的加载和内存占用情况。
  • jstat [options] pid
    jstat -class 2043 class加载、卸载、内存占用情况。
    jstat -gc 2043 GC执行情况。

后记

Java提供自动选择和自动性能优化功能。在做垃圾回收器调优之前,先列出所关注的性能指标,通过命令行告诉JVM你所关注的性能指标,由JVM自动调优,如果不满意,可以指定垃圾回收器。OutOfMemory通常是由于堆内存不足,调节-Xmx1024m-XX:MaxPermSize=128m命令行可选项即可。

Java/JVM垃圾回收机制和算法总结相关推荐

  1. JVM垃圾回收机制及算法

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

  2. JVM垃圾回收机制和算法

    一.垃圾回收机制 1.为什么需要垃圾回收 Java 程序在虚拟机中运行,是会占用内存资源的,比如创建的对象.加载的类型数据等,而且内存资源都是有限的.当创建的对象不再被引用时,就需要被回收掉,释放内存 ...

  3. java的垃圾回收机制包括:主流回收算法和收集器(jvm的一个主要优化方向)

    2019独角兽企业重金招聘Python工程师标准>>> java的垃圾回收机制是java语言的一大特色,解放了开发人员对内存的复杂控制,但如果你想要一个高级java开发人员,还是需要 ...

  4. jvm gc垃圾回收机制和参数说明amp;amp;Java JVM 垃圾回收(GC 在什么时候,对什么东西,做了什么事情)

    jvm gc(垃圾回收机制) Java JVM  垃圾回收(GC 在什么时候,对什么东西,做了什么事情) 前言:(先大概了解一下整个过程) 作者:知乎用户 链接:https://www.zhihu.c ...

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

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

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

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

  7. 【JVM】垃圾回收机制及算法

    垃圾回收机制及算法 一.垃圾回收概述 二.对象是否存活 1. 判断对象是否存活 - 引用计数算法 2.判断对象是否存活-可达性分析算法 1.可达性分析算法 2.JVM之判断对象是否存活 3.关于引用 ...

  8. 4、JVM垃圾回收机制、新生代的GC、GC(Minor GC、FullGC)、GC日志、JVM参数选项、元空间(笔记)

    4.JVM垃圾回收机制 4.1.新生代的GC 4.1.1.串行GC(SerialGC) 4.1.2.并行回收GC(Parallel Scavenge) 4.1.3.并行GC(ParNew) 4.2.G ...

  9. jvm垃圾回收机制_干货|JVM垃圾回收机制

    前言 不同于C++程序员必须自己完成内存的分配.使用和释放,JAVA语言提供了垃圾回收机制(GC,Garbage Collection),所以JAVA程序员仅需要负责分配和使用内存即可,而释放内存则由 ...

  10. jvm垃圾回收机制_JVM 垃圾回收机制之堆的分代回收

    JVM垃圾回收机制之堆的分代回收 前言 前文我们了解了Java的GC机制,对于堆中的对象,JVM采用引用计数和可达性分析两种算法来标记对象是否可以清除,本文中我们还会了解到JVM将对分成了不同的区域, ...

最新文章

  1. Android -- 带你从源码角度领悟Dagger2入门到放弃(三)
  2. Linux 技术篇-文件大小查看方法实例演示,查看指定文件大小,查看列表下所有文件夹和文件的大小
  3. OS X开发:NSProgressIndicator进度指示器控件
  4. 开发者供不应求,垃圾项目在去年已造成2.1万亿美元损失
  5. python使用ide_python使用什么ide?[关闭]
  6. 2017.9.6 外星人 思考记录
  7. python 闯关之路二(模块的应用)
  8. 使用SqlBulkCopy 批量操作大量数据
  9. HTML fieldset 标签
  10. MIDI入门: 用简谱轻松自定义midi音乐 [圣诞贺卡+铃儿响叮当]
  11. 代码生成器技术乱弹十一,伽罗华理论与代码生成器
  12. python抢票软件 app_收藏!用 Python 写一个抢票软件
  13. 实例讲解FusionInsight MRS RTD 实时决策引擎在医保行业应用
  14. 强收红包漫天要价偷转黑车……滴滴网约车被指太任性
  15. WebRTC系列-RTCDataChannel发送非音视频数据
  16. 必会工具之(一)Source Insight篇
  17. php python 源码安装教程,Python安装的图文教程分享
  18. 关于五笔和拼音输入法的最本质区别
  19. C# 条码打印的几种方式
  20. python贝叶斯模型_【机器学习速成宝典】模型篇05朴素贝叶斯【Naive Bayes】(Python版)...

热门文章

  1. 在菲律宾人民币换php怎么换,菲律宾汇率换算人民币(人民币兑换比索计算器)
  2. 复制瑞幸模式,出局的陆正耀再创业,要先开500家面馆
  3. 【论文笔记】多时相遥感影像变化检测方法综述
  4. 【分析】Ceph数据一致性检查 - Scrub的执行
  5. JavaScript 格式化显示JSON
  6. 吴恩达预热新课!万字回顾机器学习!
  7. win7 无法访问服务器共享文件夹,win7系统共享文件夹无法访问的解决方法
  8. opencv实践中遇到的问题
  9. python xlrd获取excel行数_Python 使用xlrd库读取excel,获取最大行和最大列等
  10. Latex写paper时增加脚注