JVM GC 垃圾收集梳理总结

目录
  • 什么是垃圾?
  • 什么是GC?
  • 如何发现垃圾?
  • 垃圾如何处理?
  • 常见的垃圾收集算法
    • 标记清除(mark sweep)
    • 拷贝算法 (copying)
    • 标记压缩/标记整理(mark compact)
  • JVM的内存模型如何实现垃圾回收?分代模型

什么是垃圾?

对于程序汇总分配的内存,当使用完成后,这部分内存就会成为垃圾,需要对其进行释放,否则,这部分内存将无法被重复利用,最终造成内存泄漏。

什么是GC?

GC是一种自动的存储管理机制。当一些被占用的内存不再需要时,就应该予以释放。这种存储资源管理,称为垃圾回收。

对于java而言,是自动进行垃圾回收的。

如何发现垃圾?

既然要实现垃圾的自动回收,那么第一件事就是找到垃圾,那么如何发现垃圾呢?其实就是判断这个对象是否存活。

常见的两种方式判断

  • 1)引用计数法(reference count)
  • 2)根可达性算法(root searching)
名称 实现思想 优点 缺点
引用计数法 给每个对象添加一个引用计数器,当存在一个引用时,就加1,当一个引用失效时,就减1。 判定效率高 1、无法解决相互引用、循环引用的问题。 2、存储空间开销:需要空间存储计数器。 3、时间开销:需要处理计数器的增加和减少。
根可达性算法 通过一系列名为”GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。 解决了循环引用的问题 实现较复杂,增加了计算成本。

引用计数法(reference count)的循环引用、相互引用: 没有外部引用,但是本身的计数器又不为0。

根可达性算法 由于引用计数法存在的问题,所有主流的jvm都不使用引用计数法,而是采用根可达性算法

如上图,带有GCRoots的对象表示正在被引用,而其他的对象虽然相互间有引用,但是没有根节点,仍然会被删除。

GCRoots对象: 哪些对象可以成为GCRoots呢?jvm中主要针对堆内的内存进行垃圾回收,而在虚拟机栈、本地方法栈和方法区内的对象则不会被回收,通常选择这三个区域的对象作为GCRoots。

在jvm中主要有以下四种,在方法区存在两种:

  • 1)虚拟机栈中引用的对象:虚拟机栈帧中的局部变量表所引用的对象
  • 2)本地方法栈中引用的对象:JNI (Native方法)引用的对象
  • 3)方法区中类静态和常量对象:静态变量常量引用的对象

以下图来展示在JVM内存模型(JMM)的GCRoots:

在根可达性算法中,所有的引用都是强引用,下面具体分析下jvm中的四种引用。

四种引用: 参考:分享JVM 的四种引用方式

名称 定义 特点 回收
强引用 强引用就是引用了通过new 的方式创建的对象。是指创建一个对象并把这个对象赋给一个引用变量;在root搜索算法的里面,说的引用都指的是强引用关系。 GC时,永远不会被回收,导致OOM的主要原因 1、引用消失(比如方法执行完) 2、将引用变量设置为null
软引用 如果一个对象具有软引用,内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存,比如网页缓存、图片缓存等。使用软引用能防止内存泄露,增强程序的健壮性。Java中,用SoftRefrence表示弱引用。 内存不足时(自动触发GC),会被回收 内存不足时,触发自动回收
弱引用 引用也是用来描述非必需对象的,当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。在java中,用java.lang.ref.WeakReference类来表示 无论内存是否充足,只要进行GC,都会被回收 只要进行GC,都会被回收
虚引用 虚引用和前面的软引用、弱引用不同,它并不影响对象的生命周期。在java中用java.lang.ref.PhantomReference类表示。如果一个对象与虚引用关联,则跟没有引用与之关联一样,在任何时候都可能被垃圾回收器回收。 要注意的是,虚引用必须和引用队列关联使用,设置虚引用关联的唯一目的,就是在这个对象被收集器回收的时候收到一个系统通知或者后续添加进一步的处理。Java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除之前做必要的清理工作。 如同虚设,和没有引用没什么区别 任何时候都可能被回收

垃圾如何处理?

我们通过上面学到的根可达性算法可以发现垃圾的所在,那么jvm是如何进行垃圾回收的呢?通过jvm提供的垃圾收集器(GC) 。

目前有以下种类的垃圾收集器,其中虚线表示垃圾收集器可以进行组合使用:

常见的垃圾收集算法

标记清除(mark sweep) :位置不连续 产生碎片 效率偏低(两遍扫描) 拷贝算法 (copying) :没有碎片,浪费空间 标记压缩(mark compact) :没有碎片,效率偏低(两遍扫描,指针需要调整)

标记清除(mark sweep)

顾名思义,标记清除算法分为两个阶段标记(mark) 和清除(sweep) 。

标记: Collector从引用根结点开始遍历,标记所有被引用的对象。一般是在对象的Header中记录为可达对象。

清除: Collector对堆内存从头到尾进行线性的遍历,如果发现某个对象在其Header中没有标记为可达对象,则将其回收。

对所有能找到根节点引用的内存空间进行标记,清除没有找到根节点的内存空间,其大概实现过程如下:

缺点 :

  • 1)STW(stop the word),回收时,应用挂起。
  • 2)内存越大,效率越多,需要扫描的时间越长。
  • 3)内存碎片化,会导致无法装下新申请的对象,整体内存是足够的,但并非连续的。

拷贝算法 (copying)

拷贝算法将内存空间划分为两个区间,在任意时间点,所有动态分配的对象都只能分配在其中一个区间(称为活动区间),而另外一个区间(称为空闲区间)则是空闲的。

当活动区间的内存占满时,接下来GC线程会将活动区间内的存活对象,全部复制到空闲区间,且严格按照内存地址依次排列,与此同时,GC线程将更新存活对象的内存引用地址指向新的内存地址。

其大概过程如下图所示:

缺点 浪费内存,并且存活对象越多的情况下,效率越低。

标记压缩/标记整理(mark compact)

标记过程仍然和标记-清除一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理端边界以外的内存。

实现过程大概如下:

缺点 效率不高,除了要标记存活对象,还要整理存活对象的引用地址,效率低于复制算法。

总结 以上三种算法都是根据根可达性算法实现的。当开始GC时,三种算法都会造成STW(stop the world)。

JVM的内存模型如何实现垃圾回收?分代模型

文章前面介绍了简单很多种垃圾收集器,不同的垃圾收集器有不同的分代模型:

  • 1)除Epsilon、ZGC、Shenandoah之外的GC都是使用逻辑分代模型
  • 2)G1是逻辑分代,物理不分代
  • 3)除1)2)之外不仅逻辑分代,而且物理分代

分代模型:

上图中的分代模型有些需要特别关注的点:

  • 1)整个分代模型的组成:新生代 + 老年代 + 永久代(jdk1.7)/元空间(jdk1.8) 永久代、元空间:Class 永久代:必须指定大小限制 元空间:可以设置大小,也可以不设置,无上限(受限于物理内存) 字符串常量池: jdk1.7 - 永久代,jdk1.8 - 堆 MethodArea(方法区)逻辑概念:永久代、元数据
  • 2)新生代: Eden + 2个suvivor区 YGC回收之后,大多数的对象会被回收,活着的进入s0 再次YGC,活着的对象eden + s0 -> s1 再次YGC,活着的对象eden + s1 -> s0 年龄足够 -> 老年代 (通常15,对象头Mark Word 的age只有4bit,最大是15 、CMS 6) suvivor区装不下 -> 老年代
  • 3)老年代 老年代满了FGC Full GC(STW)

GC Tuning 尽量减少FGC MinorGC = YGC MajorGC = FGC

到此这篇关于JVM GC 垃圾收集梳理总结的文章就介绍到这了,更多相关JVM GC 垃圾收集 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • GC参考手册jvm垃圾回收详解

    1,什么是垃圾回收? 顾名思义,垃圾收集(Garbage Collection)的意思就是 —— 找到垃圾并进行清理.但现有的垃圾收集实现却恰恰相反: 垃圾收集器跟踪所有正在使用的对象,并把其余部分当做垃圾 我们不抠细节, 先从基础开始, 介绍垃圾收集的一般特征.核心概念以及实现算法. 2,手动内存管理(Manual Memory Management) 当今的自动垃圾收集算法极为先进, 但我们先来看看什么是手动内存管理.在那个时候, 如果要存储共享数据, 必须显式地进行 内存分配(alloca

  • jvm垃圾回收GC调优基础原理分析

    目录 核心概念(Core Concepts) Latency(延迟) Throughput(吞吐量) Capacity(系统容量) 相关示例 Tuning for Latency(调优延迟指标) Tuning for Throughput(吞吐量调优) Tuning for Capacity(调优系统容量) 说明: Capacity: 性能,能力,系统容量; 文中翻译为”系统容量“; 意为硬件配置. GC调优(Tuning Garbage Collection)和其他性能调优是同样的原理.初学者

  • jvm垃圾回收之GC调优工具分析详解

    进行GC性能调优时, 需要明确了解, 当前的GC行为对系统和用户有多大的影响.有多种监控GC的工具和方法, 本章将逐一介绍常用的工具. JVM 在程序执行的过程中, 提供了GC行为的原生数据.那么, 我们就可以利用这些原生数据来生成各种报告.原生数据(raw data) 包括: 各个内存池的当前使用情况, 各个内存池的总容量, 每次GC暂停的持续时间, GC暂停在各个阶段的持续时间. 可以通过这些数据算出各种指标, 例如: 程序的内存分配率, 提升率等等.本章主要介绍如何获取原生数据. 后续的章

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

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

  • JVM GC 垃圾收集梳理总结

    目录 什么是垃圾? 什么是GC? 如何发现垃圾? 垃圾如何处理? 常见的垃圾收集算法 标记清除(mark sweep) 拷贝算法 (copying) 标记压缩/标记整理(mark compact) JVM的内存模型如何实现垃圾回收?分代模型 什么是垃圾? 对于程序汇总分配的内存,当使用完成后,这部分内存就会成为垃圾,需要对其进行释放,否则,这部分内存将无法被重复利用,最终造成内存泄漏. 什么是GC? GC是一种自动的存储管理机制.当一些被占用的内存不再需要时,就应该予以释放.这种存储资源管理,称

  • JVM常见垃圾收集器学习指南

    前言 垃圾收集器 是 垃圾收集算法 的具体实现 本文将对市面上常见的垃圾收集器类型进行讲解,希望你们会喜欢 垃圾收集器类型 垃圾收集器 是 垃圾收集算法 的具体实现 现在主流的垃圾收集器有 7 种: 我们会根据需求场景的不同,选择不同特点的垃圾收集器 下面我会详细介绍. 1. Serial收集器 1.1 定义 最基本.发展历史最长的垃圾收集器 1.2 优点 并发收集 在进行垃圾收集时,必须暂停其他所有工作线程(Stop The World),直到收集结束. 暂停工作线程 是在用户不可见的情况下进

  • java性能优化四种常见垃圾收集器汇总

    目录 前言 常见的垃圾回收器和算法 serial 串行垃圾收集器 Parallel 多线程垃圾收集器 CMS 收集器 G1 收集器 显式垃圾收集 前言 本篇文章我们来具体看看如何选择合适的垃圾收集器.每种垃圾收集器都有其不同的算法实现和步骤,下面我们简单描述下我们常见的四种垃圾收集器的算法过程,感兴趣的同学们最好先看下以下的两篇文章去增加理解.分别介绍了一些垃圾回收的基本概念,和各种垃圾回收器回收的过程,内容重复,本章不会在去单独讲解一遍.所以本章做一些归纳总结. JVM GC 垃圾收集梳理总结

  • Java虚拟机JVM性能优化(三):垃圾收集详解

    Java平台的垃圾收集机制显著提高了开发者的效率,但是一个实现糟糕的垃圾收集器可能过多地消耗应用程序的资源.在Java虚拟机性能优化系列的第三部分,Eva Andreasson向Java初学者介绍了Java平台的内存模型和垃圾收集机制.她解释了为什么碎片化(而不是垃圾收集)是Java应用程序性能的主要问题所在,以及为什么分代垃圾收集和压缩是目前处理Java应用程序碎片化的主要办法(但不是最有新意的). 垃圾收集(GC)的目的是释放那些不再被任何活动对象引用的Java对象所占用的内存,它是Java

  • JVM垃圾收集器详解

    说起垃圾收集(Garbage Collection,GC),大部分人都把这项技术当做Java语言的伴生产物.事实上,GC的历史远比Java久远,1960年诞生于MIT的Lisp是第一门真正使用内存动态分配和垃圾收集技术的语言.当List还在胚胎时期时,人们就在思考GC需要完成的3件事情: 哪些内存需要回收? 什么时候回收? 如何回收? 一.哪些内存需要回收? 从JVM区域结构看,可将这些区域划分为"静态内存"和"动态内存"两类.程序计数器.虚拟机栈.本地方法3个区域

  • 如何查看JVM使用的默认的垃圾收集器

    查看JVM使用的默认的垃圾收集器 查看步骤 cmd执行命令: java -XX:+PrintCommandLineFlags -version 输出如下(举例): 针对上述的-XX:UseParallelGC,这边我们引用<深入理解Java虚拟机:JVM高级特性与最佳实践>的介绍: 也就是说,打开此开关,使用的垃圾收集器是:新生代(Parallel Scavenge),老年代(Ps MarkSweep)组合. jvm默认垃圾收集器789 jdk1.7 默认垃圾收集器Parallel Scave

  • JVM的垃圾回收算法工作原理详解

    怎么判断对象是否可以被回收? 共有2种方法,引用计数法和可达性分析 1.引用计数法 所谓引用计数法就是给每一个对象设置一个引用计数器,每当有一个地方引用这个对象时,就将计数器加一,引用失效时,计数器就减一.当一个对象的引用计数器为零时,说明此对象没有被引用,也就是"死对象",将会被垃圾回收. 引用计数法有一个缺陷就是无法解决循环引用问题,也就是说当对象A引用对象B,对象B又引用者对象A,那么此时A,B对象的引用计数器都不为零,也就造成无法完成垃圾回收,所以主流的虚拟机都没有采用这种算法

  • 深入理解JVM垃圾回收算法

    目录 一.垃圾标记阶段 1.1.引用计数法 (java没有采用) 1.2.可达性分析算法 二.对象的finalization机制 2.1.对象是否"死亡" 三.使用(MAT与JProfiler)工具分析GCRoots 3.1.获取dump文件 3.2.GC Roots分析 四.垃圾清除阶段 4.1.标记-清除算法 4.2.复制算法 4.3.标记-压缩(整理,Mark-Compact)算法 4.4.以上三种垃圾回收算法对比 4.5.分代收集算法 4.6.增量收集算法 4.7.分区算法G1

  • 如何有效管理JVM中的垃圾?

    前言 都说JVM是大牛们玩的技术,其实未必,如果面试官和你你谈到Java内存管理,那么首先,我建议你首先要了解Java垃圾收集的工作原理. 因为经常在运行JAVA应用程序时,大多数开发者是使用JVM自动帮你管理GC垃圾回收器(完全不关注,JVM自动完成回收),码农们只关注业务代码实现,不需要关注JVM是怎么管理的,对大家而言,更多人只知道程序正在运行中.但是老铁们,当你写的JAVA程序开始面临性能下降时,码农与架构师的区别就来了,所有的性能问题其实归根到底就是我们的GC回收效率变低了. 因此,让

随机推荐