JVM 垃圾收集与 GC 算法

一. 垃圾收集基础

Java语言的一大特点就是可以进行自动垃圾回收处理,而无需开发人员过于关注系统资源(尤其是内存资源)的释放情况。自动垃圾收集虽然大大减轻了开发人员的工作量,但同时,它也增加了软件系统的负担。一个不合适的垃圾回收方法和策略会对系统性能造成不良影响。

1. 垃圾收集的作用

在C++语言中,程序员必须小心谨慎地处理每一项内存分配,且内存使用完后,必须手工释放曾经占用的内存空间,当内存释放不够完全时,即存在分配但永不释放的内存块,就会引起内存泄漏,严重时,会导致程序瘫痪。

虽然,目前有许多自动化检测工具可以识别这些内存泄漏的代码点,但是这种纯手工的管理内存的方法,依然被不少人所诟病。为了解决这个问题,Java语言使用了垃圾收集器用来替代C++时代的纯手工的内存管理,以减轻程序员的负担,减少出错的概率。

垃圾收集器要处理的基本问题是:

  • 哪些对象需要回收?
  • 何时回收这些对象?
  • 如何回收这些对象?

对于程序计数器、虚拟机栈、本地方法栈来说,由于他们是跟随当前线程的生命周期,当线程销毁时其占用的内存自然回收。

而 Java 堆和方法区则不一定,一个接口的多个实现类需要的内存可能不一样,一个方法中多个分支所占内存也可能不一样。所以就需要在动态分配与内存回收的基础上实施监控和内存回收。

2. 哪些内存需要回收

在堆中存放着 Java 中几乎所有对象的实例,那么已经"死去"(没有引用,不可能再被使用)的对象当然是需要回收的。

2.1 判断对象是否存活

常见的JVM垃圾判定算法包括:引用计数算法、可达性分析算法

引用计数法

  • 原理:给对象添加一个引用计数器,每当有地方引用时计数器加 1,引用失效时减 1。当该对象引用为 0 时,判定对象失效
  • 优点:实现简单,判定效率高
  • 缺点:很难解决对象之间循环引用的问题。因此目前主流的Java虚拟机都摒弃掉了这种算法。

简单的例子
一个简单的循环引用问题描述如下:有对象A和对象B,对象A中含有对象B的引用,对象B中含有对象A的引用。此时,对象A和B的引用计数器都不为0。但是,在系统中,却不存在任何第3个对象引用了A或B。也就是说,A和B是应该被回收的垃圾对象,但由于垃圾对象间的相互引用,从而使垃圾回收器无法识别,引起内存泄漏。
在这里插入图片描述

可达性分析法

  • 原理:和 GC Roots 直接或间接关联的对象是有效对象,反之则是无效对象。
  • Java 中可作为 GC Roots 的对象:
    • 1)虚拟机栈(栈帧中的本地变量表)中引用的对象;
    • 2)方法区中类静态属性引用的对象;
    • 3)方法区中常量引用的对象;
    • 4)本地方法栈中 JNI(Native 方法)引用的对象。
  • 备注:目前主流语音均使用可达性分析法来判断对象是否需要回收。
    在这里插入图片描述
    注:蓝色为可达,白色为不可达

3. 什么时候回收

当 JVM 经过可达性分析法筛选出实效对象时,并不是马上清除,而是进行标记并判断是否回收:

3.1 判断对象是否覆盖了 finalize() 方法
  • 如果覆盖了 finalize() 方法,那么将 finalize() 放到 F-Queue 队列中
  • 如果未覆盖该方法,则直接回收
3.2 执行 F-Queue 队列中的 finalize() 方法

由虚拟机自动建立一个优先级较低的线程去执行 F-Queue 中的 finalize() 方法,这里的执行只是触发这些方法并不保证会等待它执行完毕。如果 finalize() 方法作了耗时操作,虚拟机会停止执行并将该对象清除。

3.3 对象销毁或重生

在 finalize() 方法中,将 this 赋值给某一个引用,那么该对象就重生了。如果没有引用,该对象会被回收。

4. 方法区的内存回收

Java 虚拟机规范中说不需要方法区实现垃圾收集,因为方法区中存放的都是一些生命周期较长的类信息、常量、静态变量。方法区就像是堆的老年代,每次垃圾回收只有少量垃圾被清除:

  • 废弃的常量:
    当前系统中没有任何对象引用常量池中的该常量,则是废弃常量
  • 废弃的类判断规则:
    • 1)该类所有实例都被回收;
    • 2)加载该类的 ClassLoader 已经被回收;
    • 3)该类对应的 Class 对象没有引用,也无法通过反射访问该类的方法。

5. 如何回收

通过上文了解到垃圾收集、内存回收的主要区域是 Java 堆,JVM 回收的对象是那些没有引用的对象、常量、类等。

要注意的是 JVM 筛选出需要清除的对象时并不是马上进行回收,而是进行标记并判断是否覆写 finalize() 方法,然后再依据一定规则进行 GC。

接下来记录一下几种常见的 GC 算法的原理和特点

二. JVM垃圾回收算法

常见的垃圾回收算法包括:标记-清除算法,复制算法,标记-整理算法,分代收集算法。

在介绍JVM垃圾回收算法前,先介绍一个概念。

Stop-the-World

Stop-the-world意味着 JVM由于要执行GC而停止了应用程序的执行,并且这种情形会在任何一种GC算法中发生。当Stop-the-world发生时,除了GC所需的线程以外,所有线程都处于等待状态直到GC任务完成。事实上,GC优化很多时候就是指减少Stop-the-world发生的时间,从而使系统具有高吞吐 、低停顿的特点。

1. 标记—清除算法(Mark-Sweep)

标记-清除算法是几种GC算法中最基础的算法,后续的收集算法都是基于这种思路并对其不足进行改进而得到的。

  • 标记-清除算法的基本思想就跟它的名字一样,分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。

  • 标记阶段:标记的过程其实就是前面介绍的可达性分析算法的过程,遍历所有的GC Roots对象,对从GC Roots对象可达的对象都打上一个标识,一般是在对象的header中,将其记录为可达对象;

  • 清除阶段:清除的过程是对堆内存进行遍历,如果发现某个对象没有被标记为可达对象(通过读取对象header信息),则将其回收。

在这里插入图片描述
由图可以看到,回收后的空间是不连续的。不连续的内存空间的工作效率要低于连续的空间。因此,这也是该算法的最大缺点。

标记 - 清除算法主要不足有两个:

  • 效率问题:标记和清除都需要遍历,效率不高;
  • 空间问题:标记清除后会产生大量不连续的内存水平,空间碎片太多会导致大内存对象无法生成而频繁进行 GC。

2. 复制算法(Copying)

与标记-清除算法相比,复制算法是一种相对高效的回收方法。

  • 它的核心思想是:将内存划分为大小相等的两块,每次只使用其中一块,当这一块内存用完了就将还存活的对象复制到另一块上面,然后再把使用过的内存空间进行一次清理。
    在这里插入图片描述
  • 优点:简答高效,内存相对整齐
  • 缺点:
    • 1)将内存分为一半,代价略高。
    • 2)如果对象存活率高,需要复制的对象比较多,产生效率问题。

优化:

在新生代中,由于大量的对象都是"朝生夕死",也就是说一次垃圾收集后存活对象较少,因此我们可以把内存划分为三块:Eden、Survior1、Survior2,大小比例为 8:1:1。分配内存时只使用 Eden + Survior1,当这里的内存将满时,JVM 会出发一次 MinorGC,清除掉废弃对象,并将存活对象复制到另一块 Survior2 中(大对象或者老年对象会直接进入老年代,如果Survior2 空间已满,则对象也会进入老年代)。那么接下来就使用 Eden + Survior2 进行内存分配。
通过这种方式只需浪费 10% 的内存空间即可实现复制清除算法,同时避免了内存碎片的问题。
在这里插入图片描述
注:from 和 to 空间也称为 survivor 空间,即幸存者空间,用于存放未被回收的对象。

复制算法比较适用于新生代。因为在新生代中,垃圾对象通常会多于存活对象,复制算法的效果会比较好

3. 标记-整理算法(Mark-Compact)

  • 原理:和标记-清除算法一样,标记-整理算法也首先从根节点开始,从根节点开始,对所有可达的对象做一次标记,但之后,它并不是简单的清理未标记的对象,而是将所有的存活对象压缩到内存空间的一端。
    在这里插入图片描述
    注:标记-整理算法也叫标记-压缩算法

  • 优点:无需复制,保证效率。内存规整。

  • 缺点:效率不如复制算法(不仅要标记存活对象,还要整理所有存活对象的引用地址)。

三种算法排行
在了解了以上三种 GC 算法以后,作一个简单的排行:

  • 效率:复制算法 > 标记 - 整理算法 > 标记 - 清除算法

其中:标记 - 清除会产生内存碎片,需要大内存时会出发新一轮 GC

  • 内存规整率:复制算法 = 标记 - 整理 > 标记 - 清除。

  • 内存利用率:标记 - 整理算法 = 标记 - 清除算法 > 复制算法。

4. 分代收集算法(Generational Collection)

前面介绍的复制、标记-清除、标记-压缩等算法,并没有一种算法可以完全替换其他算法。它们都有各自的优缺点。因此根据垃圾回收对象的特点不同,使用不同的回收算法才是明智之举。

分代就是基于这种思想,它将内存区域根据对象的特点分成不同的内存区域,根据每块区域对象的特征不同使用不同的回收算法,以提高垃圾回收的效率。

  • 新生代(Old Generation):由于新生代产生很多临时对象,大量对象需要进行回收,所以采用复制算法是最高效的。

  • 老年代(Young Generation):回收的对象很少,都是经过几次标记后都不是可回收的状态转移到老年代的,所以仅有少量对象需要回收,故采用标记清除或者标记整理算法。

在这里插入图片描述
前置知识
JVM内存模型

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。【项目资源
大学生在线租房平台管理系统按照操作主体分为管理员和用户。管理员的功能包括报修管理、报修评价管理、字典管理、房东管理、房屋管理、房屋收藏管理、房屋留言管理、房屋租赁管理、租房论坛管理、公告信息管理、留言板管理、用户管理、管理员管理。用户的功能等。该系统采用了Mysql数据库,Java语言,Spring Boot框架等技术进行编程实现。 大学生在线租房平台管理系统可以提高大学生在线租房平台信息管理问题的解决效率,优化大学生在线租房平台信息处理流程,保证大学生在线租房平台信息数据的安全,它是一个非常可靠,非常安全的应用程序。 管理员权限操作的功能包括管理公告,管理大学生在线租房平台信息,包括房屋管理,培训管理,报修管理,薪资管理等,可以管理公告。 房屋管理界面,管理员在房屋管理界面中可以对界面中显示,可以对房屋信息的房屋状态进行查看,可以添加新的房屋信息等。报修管理界面,管理员在报修管理界面中查看报修种类信息,报修描述信息,新增报修信息等。公告管理界面,管理员在公告管理界面中新增公告,可以删除公告。公告类型管理界面,管理员在公告类型管理界面查看公告的工作状态,可以对公告的数据进行导出,可以添加新公告的信息,可以编辑公告信息,删除公告信息。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值