JVM垃圾收集(GC)

参考文献:周志明《深入理解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 中

时间: 2024-10-01 10:16:49

JVM垃圾收集(GC)的相关文章

热点推荐:为什么JVM需要GC

社区内有人发起了一个讨论,关于JVM是否一定需要GC?他们认为应用程序的回收目标是构建一个仅用来处理内存分配,而不执行任何真正的内存回收操作的 GC.即仅当可用的 Java 堆耗尽的时候,才进行顺序的 JVM 停顿操作. 首先需要理解为什么需要GC.随着应用程序所应对的业务越来越庞大.复杂,用户越来越多,没有GC就不能保证应用程序正常进行.而经常造成STW的GC又跟不上实际的需求,所以才会不断地尝试对GC进行优化. 社区的需求是尽量减少对应用程序的正常执行干扰,这也是业界目标.Oracle在JD

Java的一些基础小知识之JVM与GC (转)

  一.JVM是什么 Java虚拟机(英语:Java Virtual Machine,缩写为JVM),又名爪哇虚拟器,一种能够运行Java bytecode的虚拟机,以堆栈结构机器来进行实做.最早由太阳微系统所研发并实现第一个实现版本,是Java平台的一部份,能够运行以Java语言写作的软件程序.   Java虚拟机有自己完善的硬体架构,如处理器.堆栈.寄存器等,还具有相应的指令系统.JVM屏蔽了与具体操作系统平台相关的信息,使得Java程序只需生成在Java虚拟机上运行的目标代码(字节码),就

[JVM]垃圾收集算法

本文"垃圾收集算法"节选自<深入理解Java虚拟机:JVM高级特性与最佳实践>[作者:周志明] 由于垃圾收集算法的实现涉及大量的程序细节,而且各个平台的虚拟机操作内存的方法又各不相同,因此本节不打算过多地讨论算法的实现,只是介绍几种算法的思想及其发展过程. 1 标记-清除算法 最基础的收集算法是"标记-清除"(Mark-Sweep)算法,如它的名字一样,算法分为"标记"和"清除"两个阶段:首先标记出所有需要回收的对

JVM深入学习笔记四:JVM垃圾收集和内存分配

1. 垃圾判断算法 引用计数法,    给对象添加引用计数器,每有一个引用则+1, 没有则-1,为0为已死.python就是使用这种算法.  但是不能解决循环引用的问题. 根搜索算法.     从根开始向下搜索,如果有对象到根不可达则为死对象. HopSpot使用的是这种算法.   这里的根可以是栈中的引用对象, 方法区常量的引用对象,方法区静态属性的引用对象,JNI的引用对象. 两次标记.   虚拟机在回收对象时要做两次标记才会真的回收.无根的时候是一次,执行了finallise方法的时候会再

JVM垃圾收集器

参考文献:周志明<深入理解Java虚拟机>第二版 垃圾收集器就是 GC 具体的实现,不同厂商,不同版本,针对虚拟机不同的分区都有不一样垃圾收集器 图. 基于JDK 1.7 update 14的 HotSpot虚拟机包含的收集器 Serial 收集器 这个收集器是一个单线程收集器,在它进行收集工作时,必须暂停其他所有的工作线程,直到收集结束,这种工作方式又被称为"Stop the World" 它采用复制算法 因为单线程,所以会造成停顿,但也使得它简单而高效 适用于新生代 M

JVM垃圾收集器介绍

一.垃圾回收用到的主要算法 1.引用计数法 算法思路: 给对象中添加一个引用计数器,每当有一个地方引用他时,计数器值就加1:当引用失效时,计数器值就减1:当计数器的值为0时就可以把该对象删除. 算法优点: 实现简单,判定效率高 算法缺点: 难以解决对象之间相互循环引用的问题. 2.标记清除法 算法思路: 算法分为"标记"和"清除"两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象. 算法优点:     算法缺点: 效率低,标记和清除两个过程

JVM内存管理及GC机制

一.概述 Java GC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代码,对内存泄露和溢出的问题,也不需要像C程序员那样战战兢兢.经过这么长时间的发展,Java GC机制已经日臻完善,几乎可以自动的为我们做绝大多数的事情. 虽然java不需要开发人员显示的分配和回收内存,这对开发人员确实降低了不少编程难度,但也可能带来一些副作用: 1. 有可能不知不觉浪费了很多内存 2. JVM花

jvm系列(五):Java GC 分析

Java GC就是JVM记录仪,书画了JVM各个分区的表演. 什么是 Java GC Java GC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代码,对内存泄露和溢出的问题,也不需要像C程序员那样战战兢兢.这是因为在Java虚拟机中,存在自动内存管理和垃圾清扫机制.概括地说,该机制对JVM(Java Virtual Machine)中的内存进行标记,并确定哪些内存需要回收,根据一定

JVM实用参数(八)GC日志

原文地址:https://blog.codecentric.de/en/2014/01/useful-jvm-flags-part-8-gc-logging/ 作者:PATRICK PESCHLOW,译者:Greenster 校对:梁海舰 本系列的最后一部分是有关垃圾收集(GC)日志的JVM参数.GC日志是一个很重要的工具,它准确记录了每一次的GC的执行时间和执行结果,通过分析GC日志可以优化堆设置和GC设置,或者改进应用程序的对象分配模式. -XX:+PrintGC 参数-XX:+PrintG