JVM垃圾收集(GC)

简介: 参考文献:周志明《深入理解Java虚拟机》第二版因为 Java 具有自动垃圾回收机制,所以,垃圾收集(Garbage Collection,GC),是 Java 技术的核心之一,是...

参考文献:周志明《深入理解Java虚拟机》第二版

因为 Java 具有自动垃圾回收机制,所以,垃圾收集(Garbage Collection,GC),是 Java 技术的核心之一,是每一个 Java 程序员必知必备的一项技术,为了深入掌握 Java 技术,我们必须学习 JVM 中的 GC 是如何实现的

GC 中包含三个主要的问题:

  • 哪些内存需要回收?
  • 什么时候回收?
  • 如何回收?

我们对这三个问题逐一讨论

哪些内存需要回收?

首先我们应该清楚,在 Java 内存运行时区域的各个部分中,程序计数器(PC)、虚拟机栈(VM Stack)、本地方法栈(NM Stack)三个区域随线程而生,随线程而灭,这几个区域的内存分配和回收都具有确定性,不必过多考虑 GC 问题。而 Java 堆(Java Heap)和方法区(Method Area)就不一样了,因为,一个接口中的多个实现类需要的内存可能不一样,一个方法中的多个分支需要的内存也可能不一样,我们只有在程序运行中才能知道会创建哪些对象,所以这部分内存的分配与回收是动态的,我们需要在 Java 堆方法区 中研究 GC 问题

需要回收哪些内存,就是如何判定对象的“生”(正在被使用)或“死”(不会再被使用),有两种判定方法:

引用计数法

这是一种简单直接的判定方法,具体实现就是:给对象中添加一个引用计数器,每当它被引用时计数器就加 1 ;引用失效时,计数器就减 1,所以,计数器值为 0 的对象,就是已经没用的对象,可以被回收
这种方法实现简单,判定高效,但是却几乎不被 JVM 使用,原因是它有一个致命缺陷:无法解决对象相互循环引用问题,比如,有两个已经没用的对象 objA 和 objB ,它们虽已经不会再被程序引用,但是它们相互引用 objA.instance = objB; objB.instance = objA; 这样一来,它们的引用计数值都不为 0,无法被清理掉,它们就会一直占用空间

可达性分析法

这个判定对象“生死”算法是目前比较主流的 ,这个算法的基本思路是通过一系列的称为 GC Roots 的对象作为起始点,然后从这些结点向下搜索,搜索过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连(或是说从 GC Roots 不可达),就证明对象不可用,可以清除了
这里写图片描述
如图,Object 6, 7, 8 都是可清除的对象

那么,GC Roots 具体都是什么呢?它包括下面几种:

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量的引用对象
  • 本地方法栈中 JNI (即一般说的 Native 方法)引用的对象

ps. JVM规范中没有要求方法区必须有 GC,因为“性价比”低,过于复杂会影响性能,而且一些 JVM 将 Java 堆与方法区合为一体,因此,在本文中不讨论方法区的GC

什么时候回收?

因为 GC 主要发生在 Java 堆中,要回答这个问题就必须先明白 Java 堆的分区和 GC 的分类
Java 堆分为 新生代老年代 两个区,其中新生代又分为 一个 Eden区和 两个 Survior区(from Survior 和 to Survior),分出两个 Survior区是因为新生代回收算法采用 复制算法(后文会讲解)
GC 分为 新生代 GC(Minor GC)老年代 GC(Major GC / Full GC)
新创建的对象实例都会先进入 Eden区, 当 Eden区的空间不够新对象存入时就会触发 Minor GC,经历一次 Minor GC 而未被清除的对象会被存入 Survior区,之后每经历一次 Minor GC 未被清除,对象的“年龄”就会增长一岁,当岁数足够时,就会进入老年代,当老年代满时,就会触发一次 Full GC
因为 Java 对象大多都是朝生夕灭,所以 Minor GC 非常的频繁,一般速度也比较快,Full GC 不常发生,而且速度要比 Minor GC 慢 10 倍以上

如何回收?

这个问题是十分重要的,它就是说 GC 算法是如何实现的,GC 算法有很多,我们在此讨论最经典的几个

标记-清除算法

这是最简单基础的 GC 算法,它分为“标记”、“清除”两个阶段,就是简单的标记出可回收对象,然后将其清除,不做其他操作
这里写图片描述
这个方法虽简单,但是它有两个弊病:
① 效率不高
② 会产生大量空间碎片(如上图)
大量的空间碎片会导致大对象进入时,无法找到足够连续的内存空间,不得不触发一次 Minor GC

复制算法

它将可用内存分为大小相等的两部分,每次只使用其中一块,当这一块用完了,就将还存活的对象复制到另一个上面,然后再把使用过的内存空间一次清理掉,这种算法简单高效,不会产生内存碎片,但是代价是内存容量减小了一半,但是因为它的高效快速,所以被应用在 Minor GC 中
这里写图片描述

标记-整理算法

这个算法就是在标记-清除算法的基础上加入了整理内存空间的功能,它不会产生内存碎片,也不会牺牲空间,但是因为它要逐个整理导致回收速度缓慢,所以它被应用在老年代 Full GC 中
这里写图片描述

目录
相关文章
|
1天前
|
算法 网络协议 Java
【JVM】——GC垃圾回收机制(图解通俗易懂)
GC垃圾回收,标识出垃圾(计数机制、可达性分析)内存释放机制(标记清除、复制算法、标记整理、分代回收)
|
2月前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
86 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
1月前
|
存储 监控 Java
JVM进阶调优系列(8)如何手把手,逐行教她看懂GC日志?| IT男的专属浪漫
本文介绍了如何通过JVM参数打印GC日志,并通过示例代码展示了频繁YGC和FGC的场景。文章首先讲解了常见的GC日志参数,如`-XX:+PrintGCDetails`、`-XX:+PrintGCDateStamps`等,然后通过具体的JVM参数和代码示例,模拟了不同内存分配情况下的GC行为。最后,详细解析了GC日志的内容,帮助读者理解GC的执行过程和GC处理机制。
|
2月前
|
存储 监控 算法
JVM调优深度剖析:内存模型、垃圾收集、工具与实战
【10月更文挑战第9天】在Java开发领域,Java虚拟机(JVM)的性能调优是构建高性能、高并发系统不可或缺的一部分。作为一名资深架构师,深入理解JVM的内存模型、垃圾收集机制、调优工具及其实现原理,对于提升系统的整体性能和稳定性至关重要。本文将深入探讨这些内容,并提供针对单机几十万并发系统的JVM调优策略和Java代码示例。
63 2
|
2月前
|
Arthas 监控 Java
JVM知识体系学习七:了解JVM常用命令行参数、GC日志详解、调优三大方面(JVM规划和预调优、优化JVM环境、JVM运行出现的各种问题)、Arthas
这篇文章全面介绍了JVM的命令行参数、GC日志分析以及性能调优的各个方面,包括监控工具使用和实际案例分析。
74 3
|
2月前
|
算法 Java
JVM进阶调优系列(4)年轻代和老年代采用什么GC算法回收?
本文详细介绍了JVM中的GC算法,包括年轻代的复制算法和老年代的标记-整理算法。复制算法适用于年轻代,因其高效且能避免内存碎片;标记-整理算法则用于老年代,虽然效率较低,但能有效解决内存碎片问题。文章还解释了这两种算法的具体过程及其优缺点,并简要提及了其他GC算法。
 JVM进阶调优系列(4)年轻代和老年代采用什么GC算法回收?
|
2月前
|
存储 Java PHP
【JVM】垃圾回收机制(GC)之引用计数和可达性分析
【JVM】垃圾回收机制(GC)之引用计数和可达性分析
85 0
|
4月前
|
存储 算法 Java
JVM组成结构详解:类加载、运行时数据区、执行引擎与垃圾收集器的协同工作
【8月更文挑战第25天】Java虚拟机(JVM)是Java平台的核心,它使Java程序能在任何支持JVM的平台上运行。JVM包含复杂的结构,如类加载子系统、运行时数据区、执行引擎、本地库接口和垃圾收集器。例如,当运行含有第三方库的程序时,类加载子系统会加载必要的.class文件;运行时数据区管理程序数据,如对象实例存储在堆中;执行引擎执行字节码;本地库接口允许Java调用本地应用程序;垃圾收集器则负责清理不再使用的对象,防止内存泄漏。这些组件协同工作,确保了Java程序的高效运行。
34 3
|
4月前
|
C# UED 开发者
WPF打印功能实现秘籍:从页面到纸张,带你玩转WPF打印技术大揭秘!
【8月更文挑战第31天】在WPF应用开发中,打印功能至关重要,不仅能提升用户体验,还增强了应用的实用性。本文介绍WPF打印的基础概念与实现方法,涵盖页面元素打印、打印机设置及打印预览。通过具体案例,展示了如何利用`PrintDialog`和`PrintDocument`控件添加打印支持,并使用`PrinterSettings`类进行配置,最后通过`PrintPreviewWindow`实现打印预览功能。
480 0
|
4月前
|
C# UED 开发者
WPF动画大揭秘:掌握动画技巧,让你的界面动起来,告别枯燥与乏味!
【8月更文挑战第31天】在WPF应用开发中,动画能显著提升用户体验,使其更加生动有趣。本文将介绍WPF动画的基础知识和实现方法,包括平移、缩放、旋转等常见类型,并通过示例代码展示如何使用`DoubleAnimation`创建平移动画。此外,还将介绍动画触发器的使用,帮助开发者更好地控制动画效果,提升应用的吸引力。
245 0