【JVM】(四) :垃圾回收机制(GC)

垃圾的标准

对象被判定为垃圾的标准:

  • 没有被其他对象引用

判断对象是否为垃圾的算法:

  • 引用计数算法
  • 可达性分析算法

引用计数算法

判断对象的引用数量:

  • 通过判断对象的引用数量来决定对象是否可以被回收
  • 每个对象实例都有一个引用计数器,被引用则+1,完成引用则-1
  • 任何引用计数 为0的对象实例可以被当作垃圾收集

代码示例

    public void  ReferenceQuoteCounterProblem(){
        MyObject object1 = new MyObject();  //(1) count=1  创建对象

        MyObject object2=object1;  //(2) count=2

        object1= null;   //(3)count=1

        object2=null;   //(4)  count=0  该对象实例可以被当作垃圾收集

    }

如下图所示,每一根指向或剪断堆中的线代表引用计数器+1或-1

优点:执行效率高,程序执行受影响较小

缺点:无法检测出循环引用的情况,导致内存泄漏

代码示例

    public void  ReferenceQuoteCounterProblem2(){
        MyObject object1 = new MyObject();
        MyObject object2 = new MyObject();

        object1.childNode = object2;
        object2.childNode = object1;

    }

注:该算法机制在jvm不常用

可达性分析算法

通过判断对象的引用链是否可达来决定对象是否可以被回收

可以作为GC Root的对象

  • 虚拟机栈中引用的对象(栈帧中 的本地变量表)
  • 方法区中的常量引用的对象
  • 方法区中的类静态属性引用的对象
  • 本地方法栈中JNI(Native方法)的引用对象
  • 活跃线程的引用的对象

回收算法

垃圾回收算法

  • 标记-清除算法(Mark-Sweep)
  • 复制算法(Copying)
  • 标记-整理算法(Compacting)
  • 分代收集算法(Generational Collector)

注:这里只讲最常用的四种回收算法

标记-清除算法(Mark-Sweep)

此算法执行分两阶段。第一阶段从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除。此算法需要暂停整个应用,同时,会产生内存碎片。

  • 标记:从根集合进行扫描,对存活的对象进行标记
  • 清除:对堆内存从头到尾镜像线性遍历,回收不可达对象内存

如下图所示

注:该算法缺点明显,由于标记清除不需要对象的移动,因此会造成多个不连续的碎片。空间碎片太多,当存在分配较大的对象内存(占四个格子)时,没有足够的连续内存,而不得不提前触发另一次GC工作(一直保持clean状态), 导致OOM

复制算法(Copying)

此算法把内存空间划为两个相等的区域,每次只使用其中一个区域。垃圾回收时,遍历当前使用区域,把正在使用中的对象复制到另外一个区域中。次算法每次只处理正在使用中的对象,因此复制成本比较小,同时复制过去以后还能进行相应的内存整理,不会出现“碎片”问题。当然,此算法的缺点也是很明显的,就是需要两倍内存空间。(推倒重建,只需要移动堆顶指针,按顺序分配内容,高效简单)

  1. 分为对象面和空闲面
  2. 对象在对象面上创建
  3. 存活的对象被从对象面复制到空闲面
  4. 将对象面所有对象内存清除

如下图所示

优点:

  • 解决碎片化问题
  • 顺序分配内存,简单高效
  • 适用于对象存活低的场景(分代收集-年轻代)

标记-整理算法(Compacting)

此算法结合了“标记-清除”和“复制”两个算法的优点。也是分两阶段,第一阶段从根节点开始标记所有被引用对象,第二阶段遍历整个堆,把清除未标记对象并且把存活对象“压缩”到堆的其中一块,按顺序排放。此算法避免了“标记-清除”的碎片问题,同时也避免了“复制”算法的空间问题。(标记加移动地址造成成本更高)

  • 标记:从根集合进行扫描,对存活对象进行标记
  • 整理-清除:移动所有存活的对象,且按照内存地址依次序依次排列,然后将末端内存地址以后的内存全部回收

如下图所示

优点:

  • 避免内存的不连续性
  • 不用设置两块内存互换
  • 适用于存活率高的场景(分代收集-老年代)

分代收集算法(Generational Collector)

这种收集器把堆栈分为两个或多个域,用以存放不同寿命的对象。虚拟机生成的新对象一般放在其中的某个域中。过一段时间,继续存在的对象将获得使用期并转入更长寿命的域中。分代收集器对不同的域使用不同的算法以优化性能。这样可以减少复制对象的时间。(这里只演示JDK8中堆)

  1. 垃圾回收算法的组合拳
  2. 按照对象生命周期的不同划分区域,每个区域采用不同的垃圾回收算法
  3. 目的:提高JVM的回收效率

在Java8及以上版本的虚拟机分代垃圾回收机制中,应用程序可用的堆空间可以分为年轻代与老年代,然后年轻代有被分为Eden区,From区与To区,如下图所示:

GC分类

  • Minor GC:发生在年轻代中垃圾收集动作,采用的复制算法。
  • Full Gc:发生在老年代中。

年轻代

年轻代是类的诞生、成长、消亡的区域,一个类在这里产生,应用,最后被垃圾回收器收集,结束生命,具有有朝生夕死的性质。(尽可能快速地收集掉那些生命周期短的对象)

  • 一个Eden区和两个Survivor区组成
  • Eden与两个Survivor占比为8:1:1
  • 年轻代占整个堆的1/3大小

采用算法

  • 复制算法

年轻代三次GC回收流程图如下:

  1. 当系统创建一个对象时,这个对象的年龄也被确定了(0岁),总是在Eden区操作,当这个区满了,那么就会触发一次YoungGC,也就是年轻代的垃圾回。一般来说这时候不是所有的对象都没用了,所以就会把还能用的对象复制到From区,这时From区的对象增加1(1岁)。
  2. 这样整个Eden区就被清理干净了,可以继续创建新的对象,当Eden区再次被用完,就再触发一次YoungGC,然后呢,注意,这个时候跟刚才稍稍有点区别。这次触发YoungGC后,会将Eden区与From区还在被使用的对象复制到To区(年龄继续加1)。
  3. 再下一次YoungGC的时候,则是将Eden区与To区中的还在被使用的对象复制到From区。
  4. 经过若干次YoungGC后,有些对象在From与To之间来回游荡,这时候From区与To区亮出了底线(默认阈值15),这些家伙要是到现在还没挂掉,对不起,一起滚到(复制)老年代吧。

对象如何晋升到老年代

  • 经历一定Minnor次数依然存活的对象
  • Survivor区中存放放不下的对象
  • 新生成的大对象(-XX:+PretenuerSizeThreshold)

常用的调优参数

  • -XX:SurvivorRatio :Eden与两个Survivor的比值,默认 8:1:1
  • -XX:NewRatio:老年代和年轻代内存大小比例,默认 2:1
  • -XX:MaxTenuringThreshold:对象从年轻代晋升到老年代经过GC次数的最大阈值

老年代

存放生命周期较长的对象

采用算法

  • 标记-清理算法
  • 标记-整理算法

触发Full GC的条件

  • 老年代空间不足
  • 永久代空间不足(JDK8之前存在)
  • CMS GC时出现 promotion failed ,concurrent mode failure(可能触发)
  • Minor GC 晋升到老年代的平均大小大于老年大剩余空间
  • 调用System.gc()(可能触发)
  • 使用RMI来进行RPC或者管理的JDK应用,每个小时执行一次Full GC

原文地址:https://www.cnblogs.com/kongliuyi/p/11299320.html

时间: 2024-08-01 00:22:36

【JVM】(四) :垃圾回收机制(GC)的相关文章

JVM的垃圾回收机制(GC)

1.什么是垃圾回收                程序运行会产生各种各种的数据,那么这些数据存在于内存当中,这些数据不可能是永久存在的,无效的资源对象需要进行垃圾回收,释放内存            2.不同的编程语言都有GC垃圾回收                java语言自带GC垃圾回收器,并且有JVM自动进行垃圾回收,程序员主要关注代码实现,不关注垃圾回收 System.gc();                C/C++语言当中,程序员new一个对象,相当于申请了一块内存,如果需要释放

Java虚拟机(JVM)与垃圾回收机制(GC)的详解

一.JVM结构 根据<java虚拟机规范>规定,JVM的基本结构一般如下图所示: 从左图可知,JVM主要包括四个部分: 1.类加载器(ClassLoader):在JVM启动时或者在类运行时将需要的class加载到JVM中.(右图表示了从java源文件到JVM的整个过程,可配合理解. 关于类的加载机制,可以参考http://blog.csdn.net/tonytfjing/article/details/47212291) 2.执行引擎:负责执行class文件中包含的字节码指令(执行引擎的工作机

垃圾回收机制GC知识再总结兼谈如何用好GC(其他信息: 内存不足)

来源 一.为什么需要GC 应用程序对资源操作,通常简单分为以下几个步骤: 1.为对应的资源分配内存 2.初始化内存 3.使用资源 4.清理资源 5.释放内存 应用程序对资源(内存使用)管理的方式,常见的一般有如下几种: 1.手动管理:C,C++ 2.计数管理:COM 3.自动管理:.NET,Java,PHP,GO- 但是,手动管理和计数管理的复杂性很容易产生以下典型问题: 1.程序员忘记去释放内存 2.应用程序访问已经释放的内存 产生的后果很严重,常见的如内存泄露.数据内容乱码,而且大部分时候,

垃圾回收机制GC知识再总结兼谈如何用好GC

一.为什么需要GC 应用程序对资源操作,通常简单分为以下几个步骤: 1.为对应的资源分配内存 2.初始化内存 3.使用资源 4.清理资源 5.释放内存 应用程序对资源(内存使用)管理的方式,常见的一般有如下几种: 1.手动管理:C,C++ 2.计数管理:COM 3.自动管理:.NET,Java,PHP,GO… 但是,手动管理和计数管理的复杂性很容易产生以下典型问题: 1.程序员忘记去释放内存 2.应用程序访问已经释放的内存 产生的后果很严重,常见的如内存泄露.数据内容乱码,而且大部分时候,程序的

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

JVM的垃圾回收机制详解和调优 gc即垃圾收集机制是指jvm用于释放那些不再使用的对象所占用的内存.java语言并不要求jvm有gc,也没有规定gc如何工作.不过常用的jvm都有gc,而且大多数gc都使用类似的算法管理内存和执行收集操作. 1.JVM的gc概述 gc即垃圾收集机制是指jvm用于释放那些不再使用的对象所占用的内存.java语言并不要求jvm有gc,也没有规定gc如何工作.不过常用的jvm都有gc,而且大多数gc都使用类似的算法管理内存和执行收集操作. 在充分理解了垃圾收集算法和执行

JVM的垃圾回收机制 总结(垃圾收集、回收算法、垃圾回收器)

如果想了解Java内存模型参考:jvm内存模型-和内存分配以及jdk.jre.jvm是什么关系(阿里,美团,京东) 相信和小编一样的程序猿们在日常工作或面试当中经常会遇到JVM的垃圾回收问题,有没有在夜深人静的时候详细捋一捋JVM垃圾回收机制中的知识点呢?没时间捋也没关系,因为小编接下来会给你捋一捋. 一. 技术背景你要了解吧 二. 哪些内存需要回收? 2.1 引用计数算法 2.1.1 算法分析 2.1.2 优缺点 2.1.3 是不是很无趣,来段代码压压惊 2.2 可达性分析算法 2.3 Jav

Java垃圾回收机制(GC)详解

Java垃圾回收机制(GC)详解 简介: 垃圾回收GC(Garbage Collection)是Java语言的核心技术之一,之前我们曾专门探讨过Java 7新增的垃圾回收器G1的新特性,但在JVM的内部运行机制上看,Java的垃圾回收原理与机制并未改变.垃圾收集的目的在于清除不再使用的对象.GC通过确定对象是否被活动对象引用来确定是否收集该对象.GC首先要判断该对象是否是时候可以收集.两种常用的方法是引用计数和对象引用遍历. 垃圾收集的算法分析: Java语言规范没有明确地说明JVM使用哪种垃圾

03 JVM的垃圾回收机制

1.前言 理解JVM的垃圾回收机制(简称GC)有什么好处呢?作为一名软件开发者,满足自己的好奇心将是一个很好的理由,不过更重要的是,理解GC工作机制可以帮助你写出更好的Java程序. 在学习GC前,你应该知道一个技术名词:"stop-the-world" ,无论你选择哪种GC算法,"stop-the-world"都会发生."stop-the-world"意味着JVM停止应用程序,而去进行垃圾回收.当"stop-the-world&quo

JVM 及 垃圾回收机制原理

JVM Java 虚拟机 Java 虚拟机(Java virtual machine,JVM)是运行 Java 程序必不可少的机制.JVM实现了Java语言最重要的特征:即平台无关性.原理:编译后的 Java 程序指令并不直接在硬件系统的 CPU 上执行,而是由 JVM 执行.JVM屏蔽了与具体平台相关的信息,使Java语言编译程序只需要生成在JVM上运行的目标字节码(.class),就可以在多种平台上不加修改地运行.Java 虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行.因此实

JVM:垃圾回收机制和调优手段

转载请注明出处: jiq?钦's technical Blog - 季义钦 引言: 我们都知道JVM内存由几个部分组成:堆.方法区.栈.程序计数器.本地方法栈 JVM垃圾回收仅仅针对公共内存区域即:堆和方法区进行. 本文主要讨论两点,一是垃圾回收策略,二是调优的方法. 一.垃圾回收机制 1.1 分代管理 将堆和方法区按照对象不同年龄进行分代: u  堆中会频繁创建对象,基于一种分代的思想,按照对象存活时间将堆划分为新生代和旧生代两部分,我们不能一次垃圾回收新生代存活的对象就放入旧生代,而是要经过