你必须了解的java内存管理机制(四)

  • 时间:
  • 浏览:5

  优点:

    1、每次针对半个区域进行回收,实现简单,运行高效。

    2、不需要产生内存碎片问题报告 报告 。

  缺点:

    1、 内存会缩小为曾经的一般,代价高。

    2、 当对象存活率较高时,时需进行较多群克隆操作,下行速率 导致 变低。

  串行垃圾架构设计 器是最基本、发展历史最悠久的架构设计 器。主要蕴含 Serial和Serrial Old某种架构设计 器,分别用来架构设计 新生代和老年代。串行架构设计 器导致 是单系统线程池池架构设计 ,在进行垃圾架构设计 时,时需暂停(Stop The World)所有的工作系统线程池池,直到GC系统线程池池工作完成。运行示意图如下:

  4、并发清除(CMS Concurrent sweep)

  在并发清除阶段用户系统线程池池与清理系统线程池池也是同時 工作,清理系统线程池池回收所有的垃圾对象!

  “标记-架构设计 ”算法的标记过程与“标记-清除”算法是一样一样的,但后续步骤都是直接对可回收对象进行清理,假使 让所有的对象都向一端移动,后来直接清理掉端边界以外的内存。执行过程如下图:

  3、 产生浮动垃圾

  后边说到过在并发清理阶段,用户系统线程池池还在运行,这后来导致 就会又有新的垃圾产生,而无法在此次GC过程中被回收,这成为浮动垃圾。

  

  在这里,村里人 会先介绍几种常用的回收算法,后来了解在JVM中式如可对这几种算法进行选者 和优化的。

  

相关链接(注:文章讲解JVM以Hotspot虚拟机为例,jdk版本为1.8)

1、 你时需了解的java内存管理机制-运行时数据区

2、 你时需了解的java内存管理机制-内存分配

3、 你时需了解的java内存管理机制-垃圾标记

4、 你时需了解的java内存管理机制-垃圾回收

  

  优点:

    1、改善了“标记-清除”算法会产生内存碎片的缺点。

    2、不需要像“群克隆”算法那样下行速率 随对象存活率升高而变低。

  缺点:

    1、 依然找不到处里 “标记-清除”算法指在的缺点,那假使 回收下行速率 问题报告 报告 。还多了时需架构设计 的过程,下行速率 更低。

  后边村里人 介绍了在JVM中常用的垃圾回收算法及每某种算法的优缺点。接下里会介绍在HotSpot虚拟机中常用的几种垃圾架构设计 器,垃圾架构设计 器是垃圾回收算法的具体实现,不同的商家、不同版本的JVM所提供的垃圾架构设计 器导致 会指在差异。这几种架构设计 器分别是Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS、G1。在了解垃圾架构设计 器后来,村里人 先来区分几个概念:

本文在每个人技术博客不同步发布,详情可用力戳

亦可扫描屏幕右侧二维码关注每个人公众号,公众号内有每个人联系土辦法 ,等你来撩...

  上一篇文章中,村里人 完整性介绍了某种标记算法,后来对可达性分析算法做了较多的介绍。村里人 也知道了HotSpot在具体实现中缘何利用OopMap+RememberedSet的技术做到“准确式GC”。不管使用那此优化的技术,目标都是准确高效的标记回收对象!找不到,为了高效的回收垃圾,虚拟机又经历了那此技术及算法的演变和优化呢?(注:G1架构设计 器及回收算法本文不涉及,导致 我嘴笨 后边要能单独写一篇文章来谈!)

  4、 “Concurrent Mode Failure”失败

  真不知道村里人 在开发过程蕴含 找不到遇到过“Concurrent Mode Failure”失败的信息,不管你有找不到遇到过,反正我是遇到过!你类式 异常是那此导致 导致 的呢。在并发标记和并发清除阶段,用户系统线程池池与GC系统线程池池并发工作,这会导致 在清理的后来又会有用户的系统线程池池在拼命的创建对象,某种垃圾回收后来肯定是可用内存指在问题了,可万一这后来用户系统线程池池创建了多量的对象缘何办呢?过多 一般CMS架构设计 器的垃圾回收的动作不需要在完整性无法分配内存的后来进行,要能通过“-XX:CMSInitiatingOccupancyFraction”参数来设置CMS预留的内存空间!导致 预留的空间无法满足系统线程池池的时需,就会跳出 “Concurrent Mode Failure”失败。这后来JVM会启用后备方案,也假使 前面介绍过的Serial Old架构设计 器,曾经会导致 另一次的Full GC的产生,曾经的代价是很大的,过多 CMSInitiatingOccupancyFraction你类式 参数设置时需根据系统线程池池合理设置

  

  后边了解了CMS架构设计 器的运作过程,真不知道在了解过程中你有找不到发现或多或少问题报告 报告 ,比如CMS架构设计 器采用的是“标记-清除”算法,那会不需要产生过多 的内存碎片?比如在并发清理阶段,用户系统线程池池还在运行,会不需要在清理的过程中又产生了垃圾?总结CMS架构设计 器的几个明显的缺点如下:

  并发架构设计 器VS并行架构设计 器

  并行:指多条架构设计 系统线程池池同時 进行架构设计 工作,但此时用户系统线程池池指在停留情況。如ParNew、Parallel Scavenge、Parallel Old。

  并发:指用户系统线程池池与垃圾架构设计 系统线程池池同時 执行(并非 一定是并行,导致 会交替执行)。如CMS、G1。

  1、 对CPU资源非常敏感

  并发架构设计 嘴笨 不需要暂停用户系统线程池池,后来导致 会占用一部分CPU资源,还是会导致 应用系统线程池池调快,总吞吐量下降。CMS的默认架构设计 系统线程池池的数量=(CPU数量+3)/4。过多 ,当CPU数量大于有三个时,会有超过25%的资源用于垃圾架构设计 。当CPU数量小于或等于有三个时,默认有三个架构设计 系统线程池池。

  3、重新标记(CMS remark)

  导致 并发标记阶段,用户系统线程池池在并发运行,过多 导致 在并发标记阶段产生新的对象,过多 在重新标记阶段也会时需“Stop The World”来标记新产生的对象,且停顿时间比初始标记时间稍长,但远比并发标记短。

  优点:

    1、改善了普通群克隆算法的缺点,提高了空间利用率

  导致 老年代的对象存活周期一般相对较长,不需要像新生代对象那样“朝生夕死”,过多 对象存活率高是老年代的特点,后来老年代也找不到额外的空间要能分配担保,过多 不适合采用群克隆算法进行回收。根据老年代的特点,一般会使用"标记-清理"或"标记-架构设计 "算法来进行垃圾回收。

  2、 产生多量内存碎片

  CMS架构设计 器采用“标记-清除”算法,在清除后不需要进行压缩操作,曾经会导致 产生多量不连续的内存碎片,在分配大对象时,无法找到足够的连续内存,从而时需提前触发一次FullGC的动作。针对该问题报告 报告 ,提供了有三个参数来设置是否开启碎片架构设计 。

  1)、“-XX:+UseCMSCompactAtFullCollection”参数

  从名字能看出来,在架构设计 的后来是否开启压缩。你类式 参数默认是开启的,后来是否开启压缩还时需结合下面的参数!

  2)、“-XX:+CMSFullGCsBeforeCompaction”参数

  该参数设置执行几个次不压缩的Full GC后,来一次压缩架构设计 。你类式 参数默认为0,也假使 说每次都执行Full GC,不需要进行压缩架构设计 。

  导致 开启了压缩,则在清理阶段时需“Stop the world”,只有进行并发!

  在后边村里人 谈到有三个词,时需暂停(Stop The World)所有的工作系统线程池池,你类式 概念在后边也会多次提到,为那此时需暂停呢?一是为了方便GC动作,不然在GC过程中又会额外产生新的垃圾,导致 分配新的对象。二是导致 GC过程中对象的地址会指在变化,导致 不暂停系统线程池池,导致 会导致 引用跳出问题报告 报告 。

  并行架构设计 器是串行架构设计 器的多系统线程池池版本,除了多系统线程池池外,其余的行为、特点和串行架构设计 器一样。主要蕴含 ParNew架构设计 器、Parallel Scavenge架构设计 器、Parallel Old架构设计 器。运行示意图如下:

  

  

  “群克隆”算法将内存按容量划分为大小相等的两块,每次使用其中的一块。当一块的内存用完了,就将还存活的对象群克隆到另一块后边,后来将导致 使用过的存储空间一次性清理掉,曾经每次都是针对整个半区的内存进行回收,不需要考虑碎片问题报告 报告 。执行过程如下图:

  

  串行架构设计 器在单CPU的环境下,找不到系统线程池池切换的开销,要能获得最高的单系统线程池池架构设计 下行速率 ,后来导致 现在普遍都是多CPU(导致 多核)环境,过多 除了在桌面应用中仍然将串行架构设计 器作为默认的架构设计 器,或多或少场景导致 很少(很少不代表找不到,后边CMS会讲到)使用。

  “群克隆算法改良版”替代曾经将内存一分为二的方案,将内存分为一块较大的内存(称为Eden空间)和两块较小的内存(称为Survivor空间),每次使用Eden空间和其中一块Survivor空间。当回收时,将Eden和其中一块Survivor中还存活的对象一次性群克隆到另外一块Survivor空间上,最后清理掉Eden和刚才使用过的Survivor空间。执行过程如下图:

  

  后边介绍了CMS架构设计 器的缺点,那它当然都是它的优点啦,比如并发架构设计 、低停顿等等……过多 CMS架构设计 器适合与用户交互较多的场景,注重服务的响应下行速率 ,能给用户带来较好的体验!过多 村里人 在做WEB开发的后来,无缘无故会使用CMS架构设计 器作为老年代的架构设计 器!

  在Hotspot虚拟机中,新生代的架构设计 器都是采用的改良版的群克隆算法进行垃圾回收。将新生代一分为三,一块Eden区和两块Survivor区。Eden区与两块Survivor区的比例为8:1:1。曾经划分的土辦法 是那此呢?基于弱代理论,IBM研究表明新生代中98%的对象都是"朝生夕死",大多数分配了内存的对象并非 会存活太长时间,在指在年轻代时就会死掉。

  Serial 架构设计 器:主要针对新生代回收,采用群克隆算法,单系统线程池池架构设计 。

  Serial Old架构设计 器:主要针对老年代回收,采用“标记-架构设计 ”算法,单系统线程池池架构设计 。

  优点:

    1、基于最基础的可达性分析算法,它是最基础的架构设计 算法。

    2、后续的架构设计 算法都是基于你类式 思路并对其指在问题进行改进而得到的。

  缺点:

    1、 执行下行速率 不高。

    2、 由上图能想看 你类式 回收算法会产生多量不连续内存碎片,导致 这后来时需创建有三个大对象,则无法进行分配。

  分代回收根据对象存活周期的不同将内存划分为几个,曾经就要能根据各个年代的特点采用最适当的架构设计 算法。一般把Java堆分为新生代老年代

  YoungGC VS OldGC VS MinorGC VS MajorGC VS FullGC

  Minor GC、YoungGC:Minor GC又称为新生代GC,过多 等价于Young GC,在新生代的Eden区分配满的后来触发。在Young GC后新生代蕴含 部分存活对象会晋升到老年代,有导致 是年龄达到阈值(默认为15岁,在JVM后边15岁就步入老年生活了,O(∩_∩)O哈哈~)了,也导致 是Survivor区域满了,导致 是Survivor区域被填满,会将所有新生代中存活的对象移动到老年代中!

  Major GC、Old GC、Full GC:Old GC从字面能理解是老年代的GC,后来对Major GC和Full GC指在多种说法,有的认为Major GC等价于Old GC假使 针对老年代的GC,有的认为Major GC和Full GC是等价的。后来每个人认为Major是指老年代GC,而Full GC针对新生代、老年代、永久代整个的回收。导致 老年代的GC都是伴随一次新生代的GC,过多 习惯性的把Major GC和Full GC划上了等号。前面Young GC后来说到“在Young GC后新生代蕴含 部分存活对象会晋升到老年代”,万一老年代的空间指在问题存放新生代晋升的对象缘何办呢?过多 当准备要触发一次Young GC时,导致 发现统计数据后来Young GC的平均晋升大小比目前老年代剩余的空间大,则不需要单独触发Young GC,假使 转为触发Full GC,也假使 整堆的架构设计 !

  ParNew架构设计 器:主要针对新生代回收,采用群克隆算法,多系统线程池池架构设计 。一般老年代导致 使用CMS架构设计 器,则默认会使用ParNew作为新生代架构设计 器

  Parallel Scavenge架构设计 器:该架构设计 器与ParNew架构设计 器类式 ,也是新生代架构设计 器,采用群克隆算法,多系统线程池池架构设计 。或多或少架构设计 器关注点是尽导致 地缩短垃圾架构设计 时用户系统线程池池停顿的时间,后来Parallel Scavenge架构设计 器的目标则是达到有三个可控的吞吐量(吞吐量=CPU运行用户代码时间/(CPU运行用户代码时间+CPU垃圾架构设计 时间)),过多 该架构设计 器也成为吞吐量架构设计 器。导致 该架构设计 器找不到使用传统的GC架构设计 器代码框架,是另外独立实现的,过多 无法和CMS架构设计 器配合工作。

  Parallel Old架构设计 器:主要针对老年代回收,采用“标记-架构设计 ”算法,多系统线程池池架构设计 。该架构设计 器是Parallel Scavenge架构设计 器的老年代版本。在JDK1.6后来用来替代老年的Serial Old架构设计 器。在注重吞吐量以及CPU资源敏感的场景,一般会选者 Parallel Scavenge+Parallel Old的组合进行垃圾架构设计 。

  1、初始标记(CMS initial mark)

  仅标记GC Roots能直接关联的对象,你类式 阶段为下行速率 较快,后来仍然时需“Stop The World”,后来停顿时间较短!

  村里人 都知道,在主流的虚拟机中都是采用分代架构设计 算法来进行堆内存的回收,在第一篇文章中村里人 也用了一张图展示了JVM堆内存的划分。如下:

  2、并发标记(CMS Concurrent mark)

  进行GC Roots Tracing的过程,也假使 查找GC Roots能直接关联的对象所引用的内存。在你类式 阶段,GC系统线程池池与用户系统线程池池是同時 运行的,过多 并非 能保证能标记出所有存活的对象。

  

  前面介绍的几种架构设计 器都相对比较简单,也很好理解,过多 也没做过多的介绍。接下来介绍的架构设计 器相对前面几种架构设计 器就要比较复杂或多或少,后来使用较广,过多 介绍会较完整性!并发标记清理(Concurrent Mark Sweep)架构设计 器也称为并发低停顿架构设计 器或低延迟架构设计 器。CMS架构设计 器采用的是“标记-清理”算法,过多 不需要进行压缩操作。村里人 先来了解一下CMS架构设计 器的运作过程:

  在原始的群克隆算法中,空间一分为二,空间利用率为60 %,也假使 说有新生代中60 %的空间会被浪费,无法分配内存。Hotspot虚拟机使用改良的群克隆算法,后来设置合理的空间比例,新生代中可用的内存空间为整个新生代容量的90%,只有10%的空间会被浪费,大大的提高的新生代的空间利用率。导致 存活对象占用的内存大于新生代容量的10%缘何办?这就时需依赖或多或少内存(老年代)进行分配担保了。新生代回收动图如下:

  "标记-清除"算法分为有三个阶段,“标记”和“清除”。标记还是那个标记,在上一篇文章中导致 做了较多的介绍了,JVM在执行完标记动作后,还在"即将回收"集合的对象将被统一回收。执行过程如下图:

  在前面三篇文章中,对JVM的内存布局、内存分配、垃圾标记做了较多的介绍,垃圾都导致 标记出来了,那剩下的假使 如可高效的去回收啦!这篇文章将重点介绍如可回收旧手机、电脑、彩电、冰箱~啊呸(⊙o⊙)…将重点介绍几种垃圾回收算法、HotSpot中常用的垃圾架构设计 器的主要特点和应用场景。同時 ,这篇文章也是你类式 系列中的最后一篇文章啦!