JVM的垃圾回收机制真是通俗易懂

目录
  • 堆内存的划分
    • 划分区域的目的
  • 一、新生区的垃圾回收机制
  • 二、什么时候进入老年区呢?
    • 1经历15次GC后进入老年区
    • 2动态对象年龄判断
    • 3大对象直接进入老年代
    • 4MinorGC后存活的对象太多无法放入Survivor区了
  • 三、老年区空间分配担保原则
  • 四、老年区垃圾回收算法
  • 五、垃圾回收器
  • 总结

堆内存的划分

分为三个部分(以下名词表示同一个区):

  • 新生区、新生代、年轻代
  • 养老区、老年区、老年代
  • 永久区、永久代

划分区域的目的

唯一目的就是优化GC性能。

如果没有分代,我们所有的对象都放在一块,GC的时候我们需要对堆的所有区域进行扫描。而很多的对象都是“朝生夕死”的,如果把创建的新的对象都放在某一地方,当GC的时候就先把“朝生夕死”对象的区域进行回收,这样就会腾出很多大的空间来。

一、新生区的垃圾回收机制

新生区分为:Eden区、Survivor0区、Survivor1区(也称为from区和to区)
其中Eden区占80%的内存空间,每块Survivor各占用10%的内存空间(如:Eden占800M,每个Survivor占100M)

1.开始时创建的对象都是分配在Eden区域中,当Eden区快满了,就会触发垃圾回收Minor GC(使用复制算法进行垃圾回收)

2.Minor GC处理后,首先会把Eden区中还存活着的对象一次性转入其中一块空闲着的Survivor区。然后清空Eden区,之后创建的对象就继续放入Eden区中了,直至下次Eden又被填满。

3.Eden再次被填满时,就会再次出发Minor GC,清理后(Minor会清理Eden区和Survivor区的内存),Eden区和存在对象的Survivor区(此时的from区)中存活的对象转移到另一块空着的Survivor区中(此时的to区),并清空Eden区和之前存在对象的Survivor区(此时变为to区了,“From”和“To”会交换他们的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。)

这就是复制算法的流程。
一直要保持一个Survivor区是空的以提供复制算法垃圾回收,而这块区域的内存只占整块的10%,其他90%内存都可以被使用,课件内存利用率还是相当高的。

二、什么时候进入老年区呢?

1 经历15次GC后进入老年区

默认情况下,如果新生区中的某个对象经历了15次GC后,还是没有被回收掉,那么它就会被转入老年区。
可通过JVM参数“-XX:MaxTenuringThreshold”来设置,默认是15。

2 动态对象年龄判断

这种方法不用等到经历GC15次。
假如一批对象总大小大于当前Survivor区内存的50%,那么大于等于这批对象年龄的对象就会被转移到老年区。

例:假设Survivor0区中的两个对象都经历的3次GC(年龄3),而且这两个对象总大小50M,超过了Survivor0区内存大小的一半。那么此时Survivor0区中年龄大于等于3岁的对象就都要被全部转移到老年区。

3 大对象直接进入老年代

有一个JVM参数"-XX:PretenureSizeThreshold",默认值是0,表示任何情况都先把对象分配给Eden区。
若设置为1048576字节,也就是1M。则表示当创建的对象大于1M时,就会直接把这个对象放入到老年区,就根本不会经过新生区了。
这么做的原因:大对象在经历复制算法进行GC的时候会降低性能。

4 Minor GC后存活的对象太多无法放入Survivor区了

Minor GC后存活的对象太多,导致Survivor区放不下了,此时就会将所有的对象直接转移到老年区中。

三、老年区空间分配担保原则

执行每一次Minor GC前,JVM都先检查一下老年区可用的内存空间是否大于新生区所有对象的总大小。

原因:极端情况下,Minor GC后,新生代中所有的对象都活了下来,那就会把所有新生代中的对象放入老年区中。

  • 如果说老年区可用内存大于新生代对象总大小,那么就可以放心的执行Minor GC。
  • 但如果老年区内存小于新生区对象的总大小,这时候就会看一个参数:“-XX:HandlePromotionFailure”是否设置为true了。如果为true,就进入下一次判断,看老年区可用内存是否大于之前每次Minor GC后进入老年区对象的平均大小。如果老年代可用内存小于平均大小或是参数没有设置成true,那就会直接触发“Full GC”,就是对老年代进行垃圾回收,腾出空间后,再进行Minor GC,相当于对新生区、老年区统一做了一次清理。

三种情况递进理解:

1.如果Minor GC后,存活的对象<Survivor区大小,直接进入Survivor区即可;

2.如果Minor GC后,存活的对象>Survivor区大小,但<老年区可用内存,直接进入老年区;

3.若Minor GC后,此时老年区都放不下这些存活的对象了,就会触发Full GC;
如果Full GC后老年区内存还是不够用,就会导致OOM内存溢出。

四、老年区垃圾回收算法

标记整理算法

【原理】

一开始对象都是任意分布的,在经历完垃圾回收之后,就会标记出哪些是存活对象,哪些是垃圾对象,然后就会把这些存活的对象在内存中进行整理移动,尽量都挪到一边去靠在一起,然后再把垃圾对象进行清除,这样做的好处就是避免了垃圾回收后产生的大片内存碎片。

【缺点】

较为耗时,比复制算法慢10倍;

所以如果系统频繁出现Full GC,会严重影响系统性能,出现卡顿。所以JVM优化的一大问题就是减少Full GC频率。

五、垃圾回收器

新生区和老年区进行垃圾回收时是通过不同的垃圾回收器进行回收的

Seral 和 Seral Old垃圾回收器

  • 分别用于回收新生区和老年区。
  • 单线程运行,垃圾回收时会停止我们系统的其他线程,再执行垃圾回收(不再使用);

ParNew和CMS垃圾回收器

  • 分别用于新生区和老年区;
  • 多线程并发,性能更好,现在一般是线上生产系统的标配。

G1垃圾回收器

统一收集新生区和老年区,采用更加优秀的算法机制。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • 从JVM的内存管理角度分析Java的GC垃圾回收机制

    一个优秀的Java程序员必须了解GC的工作原理.如何优化GC的性能.如何与GC进行有限的交互,因为有一些应用程序对性能要求较高,例如嵌入式系统.实时系统等,只有全面提升内存的管理效率 ,才能提高整个应用程序的性能.本篇文章首先简单介绍GC的工作原理之后,然后再对GC的几个关键问题进行深入探讨,最后提出一些Java程序设计建议,从GC角度提高Java程序的性能.     GC的基本原理     Java的内存管理实际上就是对象的管理,其中包括对象的分配和释放.     对于程序员来说,分配对象使用

  • JVM的垃圾回收机制你了解吗

    目录 一:回收堆内存 1.如何判定对象已死(可达性分析算法) 2.对象的引用级别 3.对象的死亡过程 二:垃圾回收算法 1.标记清除算法 2.标记复制算法 3.标记整理算法 三:垃圾收集器 1.G1(GarbageFirst) 总结 一:回收堆内存 1.如何判定对象已死(可达性分析算法) 当前主流的商用程序语言的内存管理子系统,都是通过可达性分析算法来判定对象是否存活的.这个算法的基本思路就是通过一系列称为“GC Roots”的根对象作为起始节点集,从这些节点开始,根据引用关系向下搜索,搜索过程

  • JVM的垃圾回收机制详解和调优

    文章来源:matrix.org.cn 作者:ginger547 1.JVM的gc概述 gc即垃圾收集机制是指jvm用于释放那些不再使用的对象所占用的内存.java语言并不要求jvm有gc,也没有规定gc如何工作.不过常用的jvm都有gc,而且大多数gc都使用类似的算法管理内存和执行收集操作. 在充分理解了垃圾收集算法和执行过程后,才能有效的优化它的性能.有些垃圾收集专用于特殊的应用程序.比如,实时应用程序主要是为了避免垃圾收集中断,而大多数OLTP应用程序则注重整体效率.理解了应用程序的工作负荷

  • JVM的垃圾回收机制真是通俗易懂

    目录 堆内存的划分 划分区域的目的 一.新生区的垃圾回收机制 二.什么时候进入老年区呢? 1经历15次GC后进入老年区 2动态对象年龄判断 3大对象直接进入老年代 4MinorGC后存活的对象太多无法放入Survivor区了 三.老年区空间分配担保原则 四.老年区垃圾回收算法 五.垃圾回收器 总结 堆内存的划分 分为三个部分(以下名词表示同一个区): 新生区.新生代.年轻代 养老区.老年区.老年代 永久区.永久代 划分区域的目的 唯一目的就是优化GC性能. 如果没有分代,我们所有的对象都放在一块

  • Android垃圾回收机制及程序优化System.gc

    1.垃圾收集算法的核心思想 Java语言建立了垃圾收集机制,用以跟踪正在使用的对象和发现并回收不再使用(引用)的对象.该机制可以有效防范动态内存分配中可能发生的两个危险:因内存垃圾过多而引发的内存耗尽,以及不恰当的内存释放所造成的内存非法引用. 垃圾收集算法的核心思想是:对虚拟机可用内存空间,即堆空间中的对象进行识别,如果对象正在被引用,那么称其为存活对象,反之,如果对象不再被引用,则为垃圾对象,可以回收其占据的空间,用于再分配.垃圾收集算法的选择和垃圾收集系统参数的合理调节直接影响着系统性能,

  • 简单理解Java的垃圾回收机制与finalize方法的作用

    垃圾回收器要回收对象的时候,首先要调用这个类的finalize方法(你可以 写程序验证这个结论),一般的纯Java编写的Class不需要重新覆盖这个方法,因为Object已经实现了一个默认的,除非我们要实现特殊的功能(这 里面涉及到很多东西,比如对象空间树等内容). 不过用Java以外的代码编写的Class(比如JNI,C++的new方法分配的内存),垃圾回收器并不能对这些部分进行正确的回收,这时就需要我们覆盖默认的方法来实现对这部分内存的正确释放和回收(比如C++需要delete). 总之,f

  • Java 垃圾回收机制详解(动力节点Java学院整理)

    1. 垃圾回收的意义 在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前不能分配给其它对象:而在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾.JVM的一个系统级线程会自动释放该内存块.垃圾回收意味着程序不再需要的对象是"无用信息",这些信息将被丢弃.当一个对象不再被引用的时候,内存回收它占领的空间,以便空间被后来的新对象使用.事实上,除了释放没用的对象,垃圾回收也可以清除内存记录碎片.由于创建对象和垃圾回收器释放丢弃对象所占的内存空间,

  • Java 垃圾回收机制详解及实例代码

     Java 垃圾回收机制详解 乍一看,垃圾回收所做的事情应当恰如其名--查找并清除垃圾.事实上却恰恰相反.垃圾回收会跟踪所有仍在使用的对象,然后将剩余的对象标记为垃圾.牢记了这点之后,我们再来深入地了解下这个被称为"垃圾回收"的自动化内存回收在JVM中到底是如何实现的. 手动管理内存 在介绍现代版的垃圾回收之前,我们先来简单地回顾下需要手动地显式分配及释放内存的那些日子.如果你忘了去释放内存,那么这块内存就无法重用了.这块内存被占有了却没被使用.这种场景被称之为内存泄露. 下面是用C写

  • 深入理解Java垃圾回收机制以及内存泄漏

    前言 在segmentfault上看到一个问题:java有完善的GC机制,那么在java中是否会出现内存泄漏的问题,以及能否给出一个内存泄漏的案例.本问题视图给出此问题的完整答案. 垃圾回收机制简介 在程序运行过程中,每创建一个对象都会被分配一定的内存用以存储对象数据.如果只是不停的分配内存,那么程序迟早面临内存不足的问题.所以在任何语言中,都会有一个内存回收机制来释放过期对象的内存,以保证内存能够被重复利用. 内存回收机制按照实现角色的不同可以分为两种,一种是程序员手动实现内存的释放(比如C语

  • 老生常谈Java虚拟机垃圾回收机制(必看篇)

    在Java虚拟机中,对象和数组的内存都是在堆中分配的,垃圾收集器主要回收的内存就是再堆内存中.如果在Java程序运行过程中,动态创建的对象或者数组没有及时得到回收,持续积累,最终堆内存就会被占满,导致OOM. JVM提供了一种垃圾回收机制,简称GC机制.通过GC机制,能够在运行过程中将堆中的垃圾对象不断回收,从而保证程序的正常运行. 垃圾对象的判定 我们都知道,所谓"垃圾"对象,就是指我们在程序的运行过程中不再有用的对象,即不再存活的对象.那么怎么来判断堆中的对象是"垃圾&q

  • 简单介绍Java垃圾回收机制

    Java的内存分配与回收全部由JVM垃圾回收进程自动完成.与C语言不同,Java开发者不需要自己编写代码实现垃圾回收.这是Java深受大家欢迎的众多特性之一,能够帮助程序员更好地编写Java程序. 这篇教程是系列第一部分.首先会解释基本的术语,比如JDK.JVM.JRE和HotSpotVM.接着会介绍JVM结构和Java堆内存结构.理解这些基础对于理解后面的垃圾回收知识很重要. Java关键术语 JavaAPI:一系列帮助开发者创建Java应用程序的封装好的库. Java开发工具包(JDK):一

随机推荐