JVM垃圾回收机制(GC)

news2025/3/1 3:17:46

目录

GC的作用:

申请内存的时机和释放内存的时机 

内存泄露和内存溢出 

内存泄露 

内存溢出 

GC(垃圾回收的劣势) 

GC(垃圾回收) 的工作过程

垃圾回收的过程: 

第一阶段:找垃圾/判定垃圾 

方案一:基于引用计数(非Java) 

引用计数的缺陷 

1、内存空间浪费严重(空间利用率低)

2、 会出现循环引用的问题

方案二:可达性分析(Java) 

GCRoots是有哪些

一个引用置为null之后,它之前指向的对象会立刻被回收吗?  

第二阶段:回收垃圾 

1、标记清除 

标记清除的问题:释放的内存碎片化(内存不连续),影响程序运行的效率 

2、复制算法 

复制算法问题: 空间利用率低(一半),开销大(垃圾少时)

3、标记整理 

分代回收 


 

GC的作用:

GC:Garbage Clean(垃圾回收),我们在平时写代码的时候经常会进行申请内存,new操作,创建变量等等,但是内存是有限的,不断的申请会让内存耗尽,为了解决内存的消耗问题,引入了GC,这样就可以回收一些不用的内存,释放更多的空间出来。 

申请内存的时机和释放内存的时机 

申请内存的时机是比较好确定的,比如我们new,创建变量等等,但是什么时候不用这些变量就不容易知道。如果我们释放内存太早,但是后面还要用,那就尴尬了,如果我们释放的太晚了,内存不够后面申请了也是不行的。由于这些机制,就容易出现一些问题,常见的有内存泄露和内存溢出问题。

内存泄露和内存溢出 

内存泄露 

如果申请人在申请内存的过程中申请的内存越来越多,最后导致无内存可用的情况,这种现象就是内存泄露,垃圾回收就可以让我们程序猿不用关心内存泄露的问题,但是GC还是有一定的劣势的

内存溢出 

内存溢出和上述问题没有必然联系,内存溢出指的是申请内存,没有足够内存提供给使用,比如一个long类型的数据申请int类型的空间大小,这就会导致内存溢出。

GC(垃圾回收的劣势) 

1、引入额外的开销(消耗的资源更多了)

2、影响程序运行的速度(并且GC还会出现STW(stop the work)问题,这也是C++不引入GC的重要原因,C++追求速度到极限) 

GC(垃圾回收) 的工作过程

首先JVM的内存区域划分为程序计数器,栈,堆,方法区(元数据区),其中栈中内存会自动回收,不需要GC,GC主要作用的区域就是我们的堆区,堆区存放着大量我们new出来的对象,GC要回收的对象都是些没有使用的,但是占着内存空间的对象。

垃圾回收的过程: 

第一阶段:找垃圾/判定垃圾 

方案一:基于引用计数(非Java) 

这个方案就是引入一小块的内存空间,用来存放有多少个引用指向该对象,如果引用的数量为0了就代表可以进行回收。 

比如:

public static void fun(){
    
    Test t1=new Test();
    Test t2=t1;
 }

这个对于new Test()这个对象的引用计数就是2,当fun方法执行完毕的时候,栈上的栈帧就会消失,然后对new Test()的引用计数就会变成0,这个时候就可以GC进行回收了。 

由此可见引用计数的缺陷很明显

引用计数的缺陷 

1、内存空间浪费严重(空间利用率低)

使用引用计数,每次new一个对象的时候,都要引入一个计数器,这个计数器也是需要占据空间的,并且有时候占据的空间也不小,比如当我们的对象是4字节,计数器也是4字节的时候,这样的情况就非常的浪费空间。

2、 会出现循环引用的问题

通过一个例子来说明什么是循环引用:

比如我们要找宝藏:

如果这个例子不是很理解,我们用代码举例:

比如说这样一个类:

class Test{
    Test test=null;
}

在测试类中创建该类实例:

public class TestDemo {
    public static void main(String[] args) {
        Test t1=new Test();
        Test t2=new Test();
    }
}

这个时候的引用对象图:

这时我们修改引用的指向:

public class TestDemo {
    public static void main(String[] args) {
        Test t1=new Test();
        Test t2=new Test();
        t1.test=t2;
        t2.test=t1;
    }
}

这时的引用对象指向:

直观一点:

这个时候如果我们将t1和t2置为null,这个时候这两个对象的引用计数就都会变成1,变成1之后相当于这样:

两个对象互相引用,这就导致外界没有办法访问这两个对象(和上面的寻宝藏一样),所以这两个对象永远都没有办法回收,也永远不能够使用,这不是我们想要的结果 ,还会造成内存泄露。

所以Java中不使用引用计数的方式来判定垃圾。

方案二:可达性分析(Java) 

可达性分析就是通过一个线程来定期的扫描整个内存中的对象,扫描的过程类似于深度优先搜索 (起始位置一般为GCroots),把所有可以到达的对象都标记一遍,带有标记的对象就是可达的,没有标记的对象就是不可达的,也就是垃圾。(可以避免循环引用

 

虽然说可达性分析避免了循环引用的问题,但是如果对象量比较大的情况下还是会花费大量时间进行搜索,比较消耗性能。

GCRoots是有哪些

1、上的局部变量;

2、常量池当中的引用指向的变量;

3、方法区当中的静态成员指向的对象。

一个引用置为null之后,它之前指向的对象会立刻被回收吗?  

不会

一是因为即使一个引用置为空之后,并不代表这个对象就没有别的引用了。

二是因为可达性分析扫描是需要时间的,只有扫描过后判定是垃圾才会进行回收。

第二阶段:回收垃圾 

回收垃圾有三种策略:

1、标记清除

2、复制算法

3、标记整理

1、标记清除 

标记就是我们可达性分析的过程,标记完发现是垃圾的直接进行清除,释放内存即可 

 

标记清除的问题:释放的内存碎片化(内存不连续),影响程序运行的效率 

2、复制算法 

复制算法简单来说就是把内存一分为二,然后把正常的对象复制到另一边。然后把垃圾的那一边全部释放掉。(避免了内存碎片化

然后把左侧的内存全部释放:

 

复制算法问题: 空间利用率低(一半),开销大(垃圾少时)

3、标记整理 

标记整理类似于数组中元素的移动,就是把不是垃圾的对象往前移动,是垃圾的往后移动,然后把垃圾一块回收。

标记整理的策略开销也是比较大的。 

上述的方案都是单一的,实际上JVM中的方案不是单一的,而是结合上述方案的的策略,称为“分代回收”。

分代回收 

分代回收就是指对对象进行分类,按照“年龄”分成不同的类别进行回收。

对象的年龄:每熬过一轮GC扫描,年龄加1,年龄存储在对象头中 

存储对象的内存区域划分为新生代老年代 

新生代中又分为了伊甸区和幸存区(幸存区有两个) 

分代回收过程:

1、刚产生的对象放在伊甸区

2、熬过一轮GC,拷贝到幸存区利用复制算法),大部分对象熬不过一轮GC

3、在后续的GC中幸存区的对象在两个幸存区来回进行拷贝(采用复制算法),进行对象的淘汰

4、经过了多轮的GC后,如果一个对象还是没有被淘汰,那么就会被放入老年代。对于老年代的对象来说,GC扫描的次数就远低于新生代了。同时,老年代当中采用的就是"标记——整理"的方式来回收。

特殊情况:一个对象特别大(占用内存特别多),不用经过多轮GC,直接进入老年代。(因为太消耗性能了) 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/435661.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Baumer工业相机堡盟工业相机如何联合BGAPISDK和OpenCV实现图像的直方图算法增强(C++)

Baumer工业相机堡盟工业相机如何联合BGAPISDK和OpenCV实现图像的直方图算法增强(C) Baumer工业相机Baumer工业相机使用图像算法增加图像的技术背景Baumer工业相机通过BGAPI SDK联合OpenCV使用图像增强算法1.引用合适的类文件2.BGAPI SDK在图像回调中引用…

基于NXP iMX8处理器扩展外部 SGTL5000 音频接口

By Toradex胡珊逢 Apalis iMX8 计算机模块的数字音频接口 SAI(Synchronous Audio Interface)可以配置为 AC97、I2S格式,用于连接外部音频编解码器。文章接下来将介绍在 Linux BSP v6 上如何扩展第二路 SGTL5000。 iMX8 处理器具有多路 SAI 通…

I2C基础入门

I2C参数 主从模式: 主机从机 常见速率: 普通模式(100kHz)快速模式(400kHz)快速模式(1MHz)高速模式(3.4MHz)超高速模式(5MHz) 地址…

__cplusplus和extern “C“

文章目录 __cplusplus是什么extern "C"使用场景的示例通过MinGW编译及查看下目标文件中的符号用gcc编译器添加 -c选项 使my_handle.c文件编译后生成my_handle.o文件,这里的 -o是 output的意思nm命令 是GCC编译集合下最常用的查看目标文件中的符号的命令 -…

0601概述-react路由-react

1 SPA与MPA 1.1 简述 单页面应用和多页面应用是两种不同的 Web 应用程序架构。 单页面应用(SPA)是指在一个 HTML 页面中动态加载和渲染所有的应用程序内容,通过前端 JavaScript 操作来实现页面的变化和交互。SPA 不需要每次请求新的 HTML …

牛客刷题错题解析

以下是Video/Audio中会触发的事件的有? load play seeked abort 网址:https://www.nowcoder.com/questionTerminal/fc3b560267fd44e98d02a40a 方法:load() play() pause() 事件:play() playing() pause() seeked() seeking() abor…

Linux移植5.4版本内核:正点原子阿尔法IMX6ULL开发板Linux内核源码移植详细步骤(5.4版本内核)

Linux移植5.4版本内核:正点原子阿尔法IMX6ULL开发板Linux内核源码移植详细步骤(5.4版本内核) 文章目录 Linux移植5.4版本内核:正点原子阿尔法IMX6ULL开发板Linux内核源码移植详细步骤(5.4版本内核)1.出厂源…

浅理解JavaScript数组去重的方法(划重点),当面试官问如何实现数组去重时,你可以这样做...

文章目录 📋前言🎯什么是数组去重,运用场景是什么?🎯常用的数组去重方法🧩使用 Set 对象🧩使用 Object(对象、基于Hash哈希表) 或 Map🧩使用 filter 方法与 i…

概率图降低表示需要的参数指的是什么?(贝叶斯网络) 结构化概率模型

深度学习中经常要对概率密度建模。对于多维度随机变量来说,这有些困难。概率化结构(既图模型)是处理这个问题的手段之一。这引出了两个问题。为什么建模困难?图模型怎样解决了这个困难? 关于这个问题,花书…

图片怎么压缩到200K以内,这3个图片压缩方法,简单有效

你没有遇到过上传图片到网站的时候,图片太大不能上传的情况?还有,许多报名照片要求小于200K,可是照片超过这个大小,应该如何压缩呢?下面我给大家带来3个图片压缩的方法,既能快速压缩图片大小&am…

深度学习技巧应用7-K折交叉验证的实践操作

大家好,我是微学AI,今天给大家介绍一下深度学习技巧应用7-K折交叉验证的实践操作。K折交叉验证是一种机器学习中常用的模型验证和选择方式,它可以将数据集分为K个互斥的子集,其中K-1个子集作为训练集,剩下1个子集作为验…

Hive设置元数据支持中文显示

在hive中建外部表时遇见到这样一个问题,就是表字段的中文注释在desc 表结构时看不了,发现原来是Hive的元数据库没有设置支持中文显示 第一步,在元数据库metastore完成初始化后,再次登录MySQL [roothurys24 hurys_table_data]# m…

成功解决:OSError: [E050] Can’t find model ‘en_core_web_sm’.

成功解决OSError: [E050] Can’t find model ‘en_core_web_sm’. 问题描述 在安装spacy包之后,再加载’en_core_web_sm’语言模型时,报出OSError: [E050] Can’t find model ‘en_core_web_sm’. It doesn’t seem to be a Python package or a valid…

【Java】插入排序和希尔排序---图解超详细

目录 插入排序 插入排序的核心图解 希尔排序 希尔排序详细图解 插入排序 插入排序的交换精髓在于 每次随着i的扩大,i走过的路径都是有序的,这和冒泡的思想有异曲同工之处,冒泡是i走一次,数组的最后变成有序的,而插入排序是 插入排序是 i 在前面 j在后面 插入排序的核心图解…

C- 符号

文章目录 符号#ifdef-#endif\接续符转义旋转光标数字倒计时 单引号-双引号逻辑运算符&& ||短路 位运算符异或位运算最好使用定义好的宏左移右移 后置前置复杂表达式 取整0向取整(C中默认取整方式)floor地板取整ceilround 四舍五入 取模取余和取模一样吗? 运算符优先级…

两小时让你全方位的认识文件(一)

想必友友们在生活中经常会使用到各种各样的文件,那么我们是否了解它其中的奥秘呢,今天阿博就带领友友们深入地走入文件🛩️🛩️🛩️ 文章目录 一.为什么使用文件二.什么是文件三.文件的打开和关闭四.文件的顺序读写 一…

网页自动化工具DrissionPage

逛Github时偶然看到的开源项目,DrissionPage是一款新的基于 python 的网页自动化工具。 笔者已测试过,给大家推荐下。 项目地址:https://gitee.com/g1879/DrissionPage 安装测试 安装命令 pip install DrissionPage测试 from Drissio…

unity | 处理string常用的知识(持续更新)

一、转义字符和的用法 1.常规用法 我们现在有一行字,但是我对它的格式之类的有要求 例:天无绝人之路,条条道路通罗马。 我想打成: 天无绝人之路, 条条道路通罗马。 换行前,写法是: string s …

科海思—美国杜笙Tulsimer中国区总代理,制糖脱色树脂A-722

一、产品介绍 具有控制孔径的大孔强碱性Ⅰ型阴特种脱色用离子交换树脂 Tulsimer A-722是一款具有便于颜色和有机物去除的控制孔径的,专门开发的大孔强碱性Ⅰ型阴离子交换树脂。 Tulsimer A-722 (氯型)专门应用于糖浆脱色。 Tulsimer A…

Python学习简记

常用数据类型 整数类型int 二进制以0b开头八进制以0o开头十六进制以0x开头 这里还有一个值得注意的点:python中的整型是“无限长”的,因此它可以表示任何数 浮点数 python中只有float作为浮点数,没有double 主要注意python中对浮点数与Decima…