JVM的垃圾回收机制(GC机制)

2024-04-29 07:36
文章标签 机制 jvm gc 垃圾 回收 java

本文主要是介绍JVM的垃圾回收机制(GC机制),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在Java代码运行的过程中,JVM发现 某些资源不需要再使用的时候,就会自动把资源所占的内存给回收掉,就不需要程序员自行操作了。“自动回收资源”就是JVM的“垃圾回收机制”,“垃圾回收机制”也称"GC机制"

对于Java代码来说,"垃圾回收机制"的回收对象就是"堆"上的对象。因为"栈"上的局部变量,跟随栈帧的生命周期,一个方法执行结束,栈帧销毁,内存也就释放了;"方法区"中的静态变量,跟随着"类"的生命周期,因此静态变量是在程序运行期间始终存在的,无需释放。那么"垃圾"就是 "堆"中的对象。

垃圾回收机制可以分为两大步骤:"找垃圾""回收垃圾"

1. 找垃圾

"找垃圾"有两种方式,分别是 引用计数(python的方式) 和 可达性分析(Java的方式)。

1.1 引用计数

对于一个new出来的对象,会单独安排一块内存空间 来保存一个计数器。这个计数器 就用来描述当前这个对象 有几个引用指向它。当计数器为0时,也就意味着没有引用指向这个对象了,那么这个对象就是"垃圾"了。

1.2 可达性分析

在Java代码运行的过程中,会有一个或一组扫描线程周期性地扫描代码中的所有对象。这个扫描线程,会从一些特定的对象出发,尽可能地进行遍历访问,把所有能够访问到的对象 标记为 可达。反之,经过扫描之后,没有被标记的对象,就是"垃圾"了。可达性分析 是周期性地进行,会消耗一定地系统资源。

2. 回收垃圾

2.1 标记清除

把找到的"垃圾"对象直接释放掉,这就是标记清除的回收方式。这种方式并不好,因为这样的回收垃圾的方法会导致内存中有很多的内存碎片。随着程序的运行,内存碎片会越来越多,这就会导致后续申请内存空间时非常困难。回收垃圾的目的本就是为了释放内存空间,从而让其它进程申请到内存空间,但这种释放内存的方式并没有达到想要的效果。

如下图,虽然此时内存中共有3MB的空闲内存,但都不是连续的,因此其它进程只能申请到小于等于1MB的内存。

2.2 复制算法 

复制算法是对"标记清除"方式的优化,申请到内存之后,只使用内存的一半存储有效对象。出现有内存碎片时,就将有效对象归类到一起,也就是把有效对象拷贝到 存储有效对象的一半内存中,然后再将另一半内存进行释放。

复制算法能够防止出现内存碎片,但这个方式的内存利用率不高,且如果有效对象很多,拷贝的成本就很大了,效率太低。 

2.3  标记整理

标记整理 则是对 标记清除 和 复制算法 的优化,当内存中出现内存碎片时,则会将有效对象拷贝到空闲的内存中,将其覆盖,类似于顺序表删除元素的操作,这样就可以避免内存碎片了。但也涉及到了同样的问题,当需要拷贝的对象太多时,也会有很大的内存开销

2.4 分代回收

JVM在回收垃圾时,采用的方式一般就是 “分代回收”。此方法则是将堆区 划分为 两个区域,分别是"新生代""老年代"。"新生代"区域又划分为两个区域,分别是"伊甸区" 和 "幸存区",幸存区被划分为两块大小相同的区域。

刚创建出来的对象都会出现在"新生代"区域,“GC扫描线程” 会对 新生代区域的对象进行扫描。虽然从 对象的诞生 到 第一轮可达性分析扫描的过程 不会间隔较长时间,但在这段时间里,大部分对象都会成为"垃圾"。因为,这段时间对于程序而言,已经是挺长的时间了,在这个时间段中,对象的引用很快就会随着方法的执行完毕就销毁了,那么这些对象就会成为"垃圾"了。

经过一轮扫描之后,幸存下来的对象就会被拷贝到"幸存区"的一半区域中"伊甸区"的内存就可以整体释放了。虽然这个过程涉及到了拷贝对象的操作,但一般拷贝的对象并不多,因此内存开销是可承受的。GC扫描线程会在后续的扫描过程中,去扫描"幸存区"中的对象。如果幸存区中的对象经过一轮扫描后仍在存在,则会把这个对象拷贝到幸存区的另一半。在幸存区中,每经过一轮扫描,幸存下来的对象都会被拷贝到幸存区的另一半。幸存的对象在幸存区来回拷贝的过程中,会有许多对象被回收掉。如果经过多次扫描幸存区中的某些对象一直存在JVM则会把这些对象放在“老年代”中。相比于“新生代”,“老年代”区域的扫描频率要低,因为JVM认为“老年代”中的对象存活的时间较长。

将整个堆区划分为"新生代"和"老年代",也是为了降低GC扫描的开销。

分代回收则是通过上述的方式来进行垃圾回收,也是综合了 标记清除,复制算法,标记整理的优点,降低内存开销的同时,也避免了内存碎片。

这篇关于JVM的垃圾回收机制(GC机制)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/945471

相关文章

Spring的核心概念

目录 1、控制反转(IoC) 什么是控制反转 IoC与IoC容器的关系 Spring框架的控制反转 2、Bean 注解:​​​ 3、DI 4、总结 1、控制反转(IoC) 什么是控制反转 IoC(Inversion of Control,控制反转)是一种编程思想,其核心是将传统上由程序代码直接操控的对象调用权交给一个容器(外部实体),通过这个容器来实现对象的创建、装配和管

Spring AI开发前期开发指导(maven依赖下载问题解决)

文章目录 说明开发条件网络环境准备本地环境准备开发工具准备 特殊说明maven配置项目jar一致下载错误解决可行的版本搭配 说明 动力节点视频教程地址,本文章学习该教程,同时说明的maven配置问题导致的项目依赖下载失败的问题和其他问题的记录。 开发条件 网络环境准备 科学上网环境:魔法工具和稳定的场场(懂得都懂)OpenAI key或者中转key(推荐使用openai-

初识java——javaSE(4)类与对象

文章目录 前言一 类与对象1.1 面向过程与面向对象思想的区别:1.2 类的定义1.3 类的实例化——对象通过创建对象,调用对象中的成员变量与方法 1.4 this关键字this的作用一:this 的作用二构造方法:对象创建的两步方法的重载 this的作用三 : 1.5 封装getter与setter方法 1.6 public 与private是什么?1.7 包jdk中提供的供开发的包,

我希望未来十年,Java可以变成这样的

ava,这位编程界的常青树,自1995年问世以来,一直是全球开发者的宠儿。随着技术的飞速发展,Java也在持续地自我革新。接下来,让我们来聊聊,未来十年Java可能会有哪些令人兴奋的变化。(最重要的一点,希望所有工作者不再加班) 1. 工作:遍地开花 Java作为一种广泛使用的编程语言,其应用领域非常广泛,从企业级应用到移动设备,再到嵌入式系统和大数据,Java的身影无处不在。未来十年,Jav

I/O多路复用的实现机制 - poll 用法总结

一、基本知识 poll的多路复用机制与select类似,与select在本质上没有多大差别,管理多个描述符也是进行轮询(polling),根据描述符的状态进行处理,但是poll没有最大文件描述符数量上的限制。 二、poll函数 poll函数的原型声明: //使用:man 2 poll,查看poll函数的使用帮助信息(CentOS-7.6)#include <poll.h>int poll

java(实验拓展)工厂模式和原型模式

工厂模式 简单来说是一种创建型设计模式,它提供了一种创建对象的最佳实践,这种模式提供了一种抽象工厂,通过使用工厂方法来创建对象。工厂方法将对象的创建推迟到子类中,这样就可以实现对象的创建和使用解耦。 一、概念 工厂模式是一种对象创建型模式,它提供了一种创建对象的最佳实践。在工厂模式中,我们在创建对象时不使用new关键字,而是通过调用工厂方法来创建对象。工厂方法是一种在子类中定义的方法,该方法

SSM【Spring SpringMVC Mybatis】—— Spring(二)

如果对于Spring的一些基础理论感兴趣可见👇 SSM【Spring SpringMVC Mybatis】—— Spring(一) 目录 1、Spring中bean的作用域 1.1 语法 1.2 四个作用域 2、Spring中bean的生命周期 2.1 bean的生命周期 2.2 bean的后置处理器 2.3 添加后置处理器后bean的生命周期 3、Spring中自动

整合springboot-mybatis时,MySQL数据库无法连接问题

整合springboot-mybatis时,MySQL数据库无法连接问题 解决步骤 先手动停止MySQL服务,在cmd后的控制台输入services.msc 找到MySql停止服务 修改配置文件,跳过验证 修改MySQL安装目录下的my.ini配置文件,使登录时跳过权限检查; 使用命令进入MySQL mysql -u root -p 然后通过SQL语句修改root用户的

# 从浅入深 学习 SpringCloud 微服务架构(十八)

从浅入深 学习 SpringCloud 微服务架构(十八) 一、开源配置中心 Apollo:概述 1、开源配置中心 Apollo Apollo -A reliable configuration management system Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流

用Java写归并排序

用Java写归并排序 归并排序的过程如下: import java.util.*;/** Java归并排序的练习*/public class MergeSort {public void mergeSort(int[] array, int start, int end) {if(start < end) {int mid = (start + end) / 2;mergeSort(