跟踪收集算法:

复制(copying):

将堆内分成两个相同空间,从根(ThreadLocal的对象,静态对象)开始访问每一个关联的活跃对象,将空间A的活跃对象全部复制到空间B,然后一次性回收整个空间A。因为只访问活跃对象,将所有活动对象复制走之后就清空整个空间,不用去访问死对象,不需要标记骤,所以遍历空间的成本较小,但需要巨大的复制成本和较多的内存。

标记清除(mark-sweep):

收集器先从根开始访问所有对象,标记活跃对象。然后再遍历一次整个内存区域,把所有没有标记活跃的对象进行回收处理。该算法遍历整个空间的成本较大暂停时间随空间大小线性增大,而且标记结束后,相邻的不可触及对象所占空间会合并在一起,但不会进行整理,将产生越来越多的碎片。

标记整理(mark-sweep-compact):

收集器先从根开始访问所有对象,先标记活跃对象,然后清除未标记的对象,再将堆中活跃对象复制到堆的底部,使活跃对象紧凑的排列在一起,避免碎片产生。

 

常用GC收集器类型:

1.单CPU串行收集器(Serial Collector) 

使用 -XX:+UseSerialGC,策略为:

年轻代串行复制,-XX:MaxTenuringThreshold来设置对象复制的次数。

年老代串行标记整理。

2.吞吐量优先的并行收集器(Throughput Collector) 

使用 -XX:+UseParallelGC ,也是JDK -server的默认值, 它不能和CMS配合使用。策略为:

1.年轻代暂停应用程序,多个垃圾收集线程并行的复制收集,线程数默认为CPU个数,CPU很多时,可用–XX:ParallelGCThreads=线程数。
    2.年老代暂停应用程序,与串行收集器一样,单垃圾收集线程标记整理。使用-XX:+UseParallelOldGC打开年老代并行垃圾回收的线程数.

可以使用-XX:MaxGCPauseMillis 和 -XX:GCTimeRatio 来调整GC的时间。

-XX:MaxGCPauseMillis=毫秒:指定垃圾回收时的最长暂停时间,如果指定了此值的话,堆大小和垃圾回收相关参数会进行调整以达到指定值。

-XX:GCTimeRatio : 吞吐量为垃圾回收时间与非垃圾回收时间的比值,公式为1/(1+N)。例如,-XX:GCTimeRatio=19时,表示5%的时间用于垃圾回收。默认情况为99,即1%的时间用于垃圾回收。

Parallel Copying Collector用-XX:UseParNewGC参数配置,它主要用于新生代的收集,此GC可以配合CMS一起使用。

Parallel Mark-Compact Collector用-XX:UseParallelOldGC参数配置,此GC主要用于老生代对象的收集(jdk1.6)。

3.暂停时间优先的并发收集器(Concurrent Low Pause Collector-CMS)  

使用-XX:+UseConcMarkSweepGC, 主要用于老生代,策略为:
    1.年轻代同样是暂停应用程序,多个垃圾收集线程并行的复制收集。
    2.年老代则只有两次短暂停,其他时间应用程序与收集线程并发的清除。

采用两次短暂停来替代标记整理算法的长暂停,它的收集周期:  初始标记(CMS-initial-mark) -> 并发标记(CMS-concurrent-mark) -> 重新标记(CMS-remark)-> 并发清除(CMS-concurrent-sweep) ->并发重设状态等待下次CMS的触发(CMS-concurrent-reset)。

它的主要适合场景是对响应时间的重要性需求大于对吞吐量的要求,能够承受垃圾回收线程和应用线程共享处理器资源,并且应用中存在比较多的长生命周期的对象的应用。但CMS收集算法在最为耗时的内存区域遍历时采用多线程并发操作,但对于服务器CPU资源不够的情况下,其实对性能是没有提升的,反而会导致系统吞吐量的下降;

CMS默认启动的回收线程数目是  (ParallelGCThreads+ 3)/4) ,可以通过来设定

-XX:ParallelGCThreads=N 来调整年轻代的并行收集线程数, 年轻代的并行收集线程数默认是(cpu <= 8) ? cpu : 3 +((cpu * 5) / 8).

-XX:ParallelCMSThreads=N调整CMS收集线程数,CMS默认启动的回收线程数目  (ParallelGCThreads+ 3)/4)

-XX:+UseCMSCompactAtFullCollectionCMS是不会整理堆碎片的,因此为了防止堆碎片引起full gc,通过会开启CMS阶段进行合并碎片选项. 为了减少第二次暂停的时间,开启并行remark:-XX:+CMSParallelRemarkEnabled。如果remark还是过长的话,可以开启-XX:+CMSScavengeBeforeRemark选项,强制remark之前开始一次minor gc,减少remark的暂停时间,但是在remark之后也将立即开始又一次minor gc.

-XX:+CMSClassUnloadingEnabled-XX:+CMSPermGenSweepingEnabled一般情况下,持久代是不会进行GC的,通过以上参数进行强制设置。

-XX+UseCMSCompactAtFullCollection 在FULL GC的时候, 对年老代的压缩

-XX:CMSFullGCsBeforeCompaction对年老代的压缩开启的情况下,多少次FULL GC后进行内存压缩,整理

-XX:+UseCMSInitiatingOccupancyOnly 指示只有在old generation在使用了初始化的比例后concurrentcollector启动收集

-XX:CMSInitiatingOccupancyFraction=80默认CMS是在tenured generation沾满68%的时候开始进行CMS收集, 如果你的年老代增长不是那么快,并且希望降低CMS次数的话,可以适当调高此值

-XX:+AggressiveHeap 试图是使用大量的物理内存,长时间大内存使用的优化,CMS收集生效

-XX:+CMSIncrementalMode设置为增量模式, 单CPU情况使用

-XX:+UseAdaptiveSizePolicy 设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开。

-XX:MaxGCPauseMillis=100 设置每次年轻代垃圾回收的最长时间,如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值

-XX:GCTimeRatio=19 设置垃圾回收时间占程序运行时间的百分比,公式为1/(1+N),默认情况为99,即1%的时间用于垃圾回收。

JVM GC机制:

在Java语言里面,可作为GC Roots的节点主要在全局性的引用(例如常量或类静态属性)与执行上下文(例如栈帧中的本地变量表)中。如果要使用可达性分析来判断内存是否可回收的,那分析工作必须在一个能保障一致性的快照中进行——这里“一致性”的意思是整个分析期间整个执行系统看起来就像被冻结在某个时间点上,不可以出现分析过程中,对象引用关系还在不断变化的情况,这点不满足的话分析结果准确性就无法保证。这点也是导致GC进行时必须暂停的其中一个重要原因.

HOTSPOT使用准确式GC, 从外部记录下类型信息,存成映射表。HotSpot把这样的数据结构叫做OopMap,需要虚拟机里的解释器和JIT编译器都有相应的支持,在类加载完成的时候,HotSpot就把对象内什么偏移量上是什么类型的数据计算出来,在JIT编译过程中,也会在特定的位置记录下栈里和寄存器里哪些位置是引用, 这样GC在扫描时就就可以直接得知这些信息了。HotSpot是用“解释式”的方式来使用OopMap的,每次都循环变量里面的项来扫描对应的偏移量。

解释式: 每次都遍历原始的映射表,循环的一个个偏移量扫描过去,HOTSPOT采用

编译式: 为每个映射表生成一块定制的扫描代码(想像扫描映射表的循环被展开的样子),以后每次要用映射表就直接执行生成的扫描代码。

在OopMap的协助下,HotSpot可以快速准确地地完成GC Roots枚举,但一个很现实的问题随之而来,可能导致引用关系变化,或者说OopMap内容变化的指令非常多,如果为每一条指令都生成对应的OopMap,那将会需要大量的额外空间,这样GC的空间成本将会变得很高。

所以HotSpot也的确没有为每条指令都生成OopMap,前面已经提到,只是在“特定的位置”记录了这些信息,这些位置被称为安全点(Safepoint),即程序执行时并非在所有的地方都能停顿下来开始GC,只有在到达安全点时才能暂停。

每个被JIT编译过后的方法也会在安全点记录下OopMap,记录了执行到该方法的某条指令的时候,栈上和寄存器里哪些位置是引用。这样GC在扫描栈的时候就会查询这些OopMap就知道哪里是引用了。Safepoint的选定既不能太少以至于让GC等待时间太长,也不能过于频繁以至于过分增大运行时的负荷。所以安全点的选定基本上是以程序“是否具有让程序长时间执行的特征”为标准进行选定:

1、循环的末尾

2、方法临返回前 / 调用方法的call指令后

3、可能抛异常的位置

如何让GC发生时,让所有线程(这里不包括执行JNI调用的线程)都跑到最近的安全点上再停顿下来。HotSpot采用主动式中断,主动式中断的是当GC需要中断线程的时候,不直接对线程操作,仅仅简单地设置一个标志,各个线程执行时主动去轮询这个标志,发现中断标志为真时就自己中断挂起。

对Java线程中的JNI方法,它们既不是由JVM里的解释器执行的,也不是由JVM的JIT编译器生成的,所以会缺少OopMap信息,HotSpot的解决方法是:所有经过JNI调用边界(调用JNI方法传入的参数、从JNI方法传回的返回值)的引用都必须用“句柄”(handle)包装起来。JNI需要调用Java API的时候也必须自己用句柄包装指针。在这种实现中,JNI方法里写的“jobject”实际上不是直接指向对象的指针,而是先指向一个句柄,通过句柄才能间接访问到对象。这样在扫描到JNI方法的时候就不需要扫描它的栈帧了,只要扫描句柄表就可以得到所有从JNI方法能访问到的GC堆里的对象。

内存回收如何进行是由虚拟机所采用的GC收集器所决定的,而通常虚拟机中往往不止有一种GC收集器,目前HotSpot里面就包含有常用的garbage collectors:

·        serial collector :针对younggeneration的串行垃圾收集器,使用stop-the-world(就是暂停整个应用程序的执行)的形式,利用单线程通过复制live objects到survivor space或tenured generation的方法来进行垃圾收集。

·        parallel scavenge collector :针对younggeneration的并行垃圾收集器,利用多个GC线程来进行垃圾收集,每个线程的GC方法和serial collector一样。

·        parallel  new collector :针对younggeneration的增强的并行垃圾收集器,以便可以和CMS一起使用。

·        serial old collector :针对tenuredgeneration的串行垃圾收集器,使用stop-the-world形式,利用单线程通过mark-sweep-compact的方法进行垃圾收集。

·        parallel old collector :针对tenuredgeneration的并行垃圾收集器,利用多线程进行垃圾收集,方法和serial old collector一样。

·        parallel compacting collector :对于younggeneration使用和parallel new collector一样的算法,对于tenured generation使用了新的算法(mark-summary-compact),该收集器用来替代parallel new collector和parallel oldcollector。

·        concurrent mark-sweep collector :对于younggeneration使用和parallel new collector一样的算法,对于tenured generation使用跟应用程序并发的方式,收集期间也有引起stop-the-world的暂停Mark阶段,也有伴随着应用程序运行的并发 Mark和并发Sweep阶段,降低了应用程序暂停的时间。

可以看出这些垃圾收集器分为3种类型:串行,并行,并发;

JVM调优系列:(四)GC垃圾回收相关推荐

  1. JVM 调优系列之图解垃圾回收

    转载自  JVM 调优系列之图解垃圾回收 摘要: jvm必知系列,总结一些常见jvm回收机制,方便查阅 从这篇开始我们开始探讨一些jvm调优的问题.在jvm调优中一个离不开的重点是垃圾回收,当垃圾回收 ...

  2. java虚拟机学习-JVM调优总结-新一代的垃圾回收算法(11)

    java虚拟机学习-深入理解JVM(1) java虚拟机学习-慢慢琢磨JVM(2) java虚拟机学习-慢慢琢磨JVM(2-1)ClassLoader的工作机制 java虚拟机学习-JVM内存管理:深 ...

  3. JVM 调优实战--什么是垃圾回收及Java的自动垃圾回收GC

    什么是垃圾回收 程序的运行必然要申请内存资源,无效的对象资源如果不及时处理就会一直占用内存资源,最终将导致内存溢出,所以对内存资源的管理就变得非常重要了. C/C++语言的垃圾回收 在C/C++语言中 ...

  4. JVM 调优实战--常见的垃圾回收算法及垃圾收集器组合

    什么是垃圾 C语言申请内存:malloc free C++: new delete c/C++ 手动回收内存 Java: new ? 自动内存回收,编程上简单,系统不容易出错,手动释放内存,容易出两种 ...

  5. java知识点8——垃圾回收原理和算法、通用的分代垃圾回收机制、 JVM调优和Full GC、开发中容易造成内存泄露的操作

    垃圾回收原理和算法 内存管理 Java的内存管理很大程度指的就是对象的管理,其中包括对象空间的分配和释放. 对象空间的分配:使用new关键字创建对象即可 对象空间的释放:将对象赋值null即可 垃圾回 ...

  6. JVM 调优 2:GC 如何判断对象是否为垃圾,三色标记算法应用原理及存在的问题?

    文章目录 前言 一.如何判断一个对象是否为垃圾? 1.1.reference count(引用计数) 1.2.reference count(引用计数)存在的问题 二.Root Searching(根 ...

  7. JVM调优系列--Java命令选项(参数)--大全/详解/常用

    原文网址:JVM调优系列--Java命令选项(参数)--大全/详解/常用_IT利刃出鞘的博客-CSDN博客 简介 说明        本文介绍Java的java命令用法,包括:常用用法.选项大全. J ...

  8. JVM 调优系列之监控工具

    转载自  JVM 调优系列之监控工具 摘要: 项目部署线上之后,我们该如何基于监控工具来快速定位问题.... 通过上一篇的jvm垃圾回收知识,我们了解了jvm对内存分配以及垃圾回收是怎么来处理的.理论 ...

  9. JVM 调优系列 1:“精通 JVM 调优,有过 JVM 调优经验”,简历敢写吗?薪资涨 5k 的技巧!

    文章目录 前言 一.部分大厂对于 JVM GC 的面试题 1.1.百度 1.2.顺丰 1.3.京东 1.4.淘宝 1.5.阿里.蘑菇街 二.Garbage Collectors(GC)作何使用 三.G ...

最新文章

  1. c# 解析JSON的几种办法(转载)
  2. 机器学习的数学基础 - 信息论
  3. c语言交换a b(运算符),关于编程语言:是否有一个复合赋值运算符用于a = b
  4. 微信小程序swiper图片尺寸_微信小程序之swiper轮播图中的图片自适应高度的方法...
  5. 数据库表字段命名规则
  6. 【Python】我的Pandas学习经历及动手实践
  7. windows 下 logstash 安装启动
  8. 百度之星2019 初赛一 题解
  9. 我当圣诞老人跳舞啦!
  10. cxf超时设置不起效_晚上不限时,白天1小时!上海限时长停车场来了
  11. dds通信中间件_车内的中间件协议:是面向服务,还是以数据为中心,或是RESTful?...
  12. 图书馆管理系统代码html语言,图书管理系统html - WEB源码|源代码 - 源码中国
  13. MobileNetV3——论文翻译
  14. 毕业论文ppt的研究方法及过程计算机专业,毕业论文答辩ppt(要求和制作技巧)...
  15. 支付宝开发中,抱歉,该商户未开通支付宝服务,无法支付
  16. “阳”后第1 2 3 4 5 6 7天的症状详解
  17. 台式机开机黑屏一直闪小横杠,键盘灯鼠标均正常,主板亮
  18. 联通沃云开启80端口
  19. SWUST OJ 1012: 哈希表(链地址法处理冲突)
  20. 如何添加打印纸规格尺寸?

热门文章

  1. STM32 ADC采样使用内部参考电压
  2. servlet中弹出对话框
  3. GB2312,GBK,UTF-8的关系
  4. python通过ip池爬_Python爬虫 | IP池的使用
  5. python中if的效率_Python 代码性能优化技巧
  6. 机器学习如何计算特征的重要性_干货 :机器学习中的特征工程总结
  7. c++ 0x8000ffff灾难性故障_《可靠性设计》——故障模式影响分析
  8. 鸿蒙1号六年级下册课时练答案,【奥数天天练】小学1~6年级思维能力特训|第310期...
  9. java双等号和equals_JAVA编程基础篇:hashCode的特性和作用
  10. 二分法分页 mysql_LeetCode 04寻找两个正序数组的中位数(困难)二分法