Java 垃圾回收机制 GC 及常用的垃圾回收算法

在 Java 中,所有的对象都是要存在内存中的(也可以说内存中存储的是一个个对象),因此我们将内存回收,也可以叫做死亡对象的回收;

GC 回收的目标是堆上的对象;而栈中的局部变量会跟随栈帧的声明周期结束,静态变量生命周期是整个程序,因此都不需要 GC 回收;

GC 回收操作可分为两步——找到垃圾对象和回收垃圾对象

1. 找到垃圾对象

1)引用计数(Python 采用这种方式)

为 new 出来的对象,单独安排一块空间,保存计数器,表示有多少个引用指向该对象,当一个对象的引用计数器为 0,就可以视为垃圾了;

引用计数存在的问题:

a. 比较浪费内存

b. 存在循环引用问题,下面是个循环引用的示例:

public class Main {public Main t;public static void main(String[] args) {Main a = new Main();Main b = new Main();a.t = b;b.t = a;a = null;b = null;}
}
2)可达性分析(Java 采用这种方式)

有一个或一组线程,周期性的扫描代码中的所有对象(从一些特定的对象出发,尽可能的进行访问的遍历,把所有能够访问到的对象都标记为 "可达",未被标记的对象则为 "垃圾");这些特定的对象称为 "GC Roots",从这些节点开始向下搜索,搜索走过的路径称之为 "引用链",当一个对象到GC Roots 没有任何的引用链相连时(说明 GC Roots到这个对象不可达),则该对象是不可用的,需要被回收;

在 Java 中,可作为 GC Roots 的对象包含以下几种

  1. 虚拟机栈(栈帧中的本地变量表)中引用的对象;
  2. 方法区中类静态属性引用的对象;
  3. 方法区中常量引用的对象;
  4. 本地方法栈中 JNI(Native 方法)引用的对象;

2. 回收垃圾

1)标记清除

该算法分为 "标记" 和 "清除" 两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象;

缺点:

a. 效率问题:标记和清除这两个过程的效率都不高;

b. 空间问题:标记清除后会产生大量不连续的内存碎片,导致剩余的内存空间不连续,这可能会导致以后在程序运行中,需要分配较大对象时,无法找到足够连续的内存;

2)复制算法

"复制" 算法是为了解决 "标记,清理" 的效率问题。它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这块内存需要进行垃圾回收时,会将此区域还存活着的对象复制到另⼀块上面, 然后再把已经使用过的内存区域一次清理掉。(通过复制的方式,把有效的对象归类到一起,再统一释放剩下的空间)这样做的好处是每次都是对整个半区进行内存回收,不会出现内存碎片问题,此算法实现简单,运行高效。

缺点:

有效对象非常多时,复制拷贝的开销会非常大;

3)标记整理:

此算法的标记过程仍与 "标记,清除" 过程一致,但后续步骤不是直接对可回收对象进行清理,而是让所有存活对象都向一端移动,然后直接清理掉该端边界以外的内存;

2    4    6    

如图,若 1,3,5是无效的垃圾,则经该算法整理后会变为:

246      

 缺点:搬运的开销仍很大

4)分代回收算法(Java 采取的方式)

分代回收算法可以说是上述三种方法的结合体,通过区域划分,实现不同区域和不同的垃圾回收策 略,从而实现更好的垃圾回收

该算法把 Java 堆分为新生代和老年代;其中新生代放新建的对象,老年代存放在经新生代的多次GC 之后还存活的对象;

新生代又分为 伊甸区和幸存区(又分为大小相等的两块);

在新生代中,每次垃圾回收都有大批对象死去,只有少量存活,因此采用复制算法;

在伊甸区中,使用复制算法将有效对象复制到幸存区,然后将整个伊甸区释放;

在幸存区中,每次只使用其中一块,也使用复制算法,将活过 GC 的有效对象,拷贝到另一块幸存区,然后将该快幸存区释放;

而老年代中对象存活率高、没有额外空间对它进行分配担保,就采用 "标记-清理" 或者 "标记-整理" 算法;

当某个对象已经在幸存区存活很多轮 GC 之后,JVM 就认为该对象短时间内不会释放,会把该对象拷贝的老年代, GC 仍会使用标记算法扫描老年代,但是扫描老年代的频率会比扫描新生代的频率低很多;

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

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

相关文章

智谱AI——智能体开发探索

智谱AI——智能体开发探索 智谱AI开放平台:https://open.bigmodel.cn/ 点击网页右上角“开发工作台”。进入工作台后,可点击进入“文档中心”。 文档中心/接口文档:https://open.bigmodel.cn/dev/api 使用指南:https://open.b…

vue2组件封装实战系列目录

写在前面 本系列教程是vue2的一套技术文章,参考的对象是曾经极为辉煌的elementui组件库,虽然现在已经都开始使用vue3了,但是研究这套组件库,对于提升我们的封装思维还是有很大作用的!!所以活不多少&#x…

OutOfDirectMemoryError堆外内存溢出Bug解决

问题描述: springboot 2.0,整合redis实现缓存,当并发请求上来达到一定量级,会导致系统爆发该异常。 产生原因: 1.springboot 2.0以后默认使用lettuce作为操作redis的客户端,lettuce使用netty进行网络通讯…

【开源】医院电子病历管理系统 SSM+JSP+MySQL

目录 一、项目介绍 科室模块 医生模块 预约挂号模块 就诊记录模块 就诊评价模块 二、项目界面 三、核心代码 一、项目介绍 经典老框架SSM打造入门项目《医院电子病历管理系统》,分为用户网页和管理后台,包括科室模块、医生模块、预约挂号模块、…

[MQTT]服务器EMQX搭建SSL/TLS连接过程(wss://)

👉原文阅读 💡章前提示 本文采用8084端口进行连接,是EMQX 默认提供了四个常用的监听器之一,如果需要添加其他类型的监听器,可参考官方文档🔗管理 | EMQX 文档。 本文使用自签名CA,需要提前在L…

【Redis】构建强韧的远程Redis连接与端口保障机制完美指南

【Redis】构建强韧的远程Redis连接与端口保障机制完美指南 大家好 我是寸铁👊 总结了【Redis】构建强韧的远程Redis连接与端口保障机制完美指南✨ 喜欢的小伙伴可以点点关注 💝 前言 在当今的软件开发领域中,远程访问和操作数据存储是极为常见…

华为OD刷题C卷 - 每日刷题 17(字符串序列判定,最长的指定瑕疵度的元音子串)

1、(字符串序列判定): 这段代码是解决“字符串序列判定”的问题。它提供了一个Java类Main,其中包含main方法和getResult方法,用于判断字符串S是否是字符串L的有效子串。 main方法首先读取两个字符串S和L,…

分布式锁与信号量详解

一、引言 在分布式系统中,数据的一致性和并发控制是两大核心挑战。分布式锁和信号量作为解决这些问题的关键工具,被广泛应用于各种分布式场景中。本文将对分布式锁和信号量的概念、原理、实现方式以及应用场景进行详细介绍,并通过具体的代码…

STM32项目分享:智能家居安防系统

目录 一、前言 二、项目简介 1.功能详解 2.主要器件 三、原理图设计 四、PCB硬件设计 1.PCB图 2.PCB板及元器件图 五、程序设计 六、实验效果 七、资料内容 项目分享 一、前言 项目成品图片: 哔哩哔哩视频链接: https://www.bilibili.c…

Decimal要从str转换以避免精度问题

最近遇到一个python的小数的问题,本来应该很简单的小于判断,无论如何都不正确,而且浮点小数都没问题,但decimal小数有问题,给我整蒙了,后来才发现是对decimal不了解所致,如果你还用float转decim…

翻转二叉树-力扣

翻转二叉树,通过前序遍历的顺序,从根节点开始,将节点的左右子节点一次进行交换即可。 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), …

Flowable项目启动报错#java.time.LocalDateTime cannot be cast to java.lang.String

Flowable 项目启动后报错 flow项目第一次启动创建表成功,但是第二次启动时报错信息如下: 1、Error creating bean with name ‘appRepositoryServiceBean’ defined in class 2、Error creating bean with name ‘flowableAppEngine’: FactoryBean t…

立创小tips

立创小tips 原理图中 1-修改图纸属性 保存完,绘制原理图的界面就出现了,然后我们鼠标点击原理图的边缘变成红色就可以高边表格的属性了。 2-鼠标右键可以移动整个原理图 3-查看封装 点击任意一个元器件,在右侧就会显示封装属性&#xff…

基于fabric封装一个简单的图片编辑器(vue 篇)

介绍 前言vue demo版本react 版本 前言 对 fabric.js 进行二次封装,实现图片编辑器的核心功能。核心代码 不依赖 ui响应式框架vue ,react 都适用。 只写了核心编辑相关代码便于大家后续白嫖二次开发 核心代码我就没有打包发布 会 和 业务代码一起放到项目中。 vu…

socket通信(C语言+Python)

在socket文件夹下创建server.c和client.c。 服务端代码&#xff08;server.c&#xff09;&#xff1a; #include <stdio.h> #include <Winsock2.h> void main() {WORD wVersionRequested;WSADATA wsaData;int err;wVersionRequested MAKEWORD( 1, 1 );err WSAS…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《基于日间-日内不确定集的中长期电源扩展规划》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

简说SQLServer

SQLServer是Microsoft公司推出的一种关系型数据库系统&#xff0c;下面将对其进行详细的解析&#xff0c;包括其主要特性、功能、版本介绍等方面&#xff1a; 一、主要特性 高性能设计&#xff1a;SQLServer充分利用WindowsNT的优势&#xff0c;提供高性能的数据库操作。系统…

SpringBoot整合RabbitMQ (持续更新中)

RabbitMQ 官网地址&#xff1a;RabbitMQ: One broker to queue them all | RabbitMQ RabbitMQ 与 Erlang 版本兼容关系​ 3.13.0 26.0 26.2.x The 3.13 release series is compatible with Erlang 26. OpenSSL 3 support in Erlang is considered to be mature and ready for…

kafka-重试和死信主题(SpringBoot整合Kafka)

文章目录 1、重试和死信主题2、死信队列3、代码演示3.1、appication.yml3.2、引入spring-kafka依赖3.3、创建SpringBoot启动类3.4、创建生产者发送消息3.5、创建消费者消费消息 1、重试和死信主题 kafka默认支持重试和死信主题 重试主题&#xff1a;当消费者消费消息异常时&…

数据结构(C语言)之对归并排序的介绍与理解

目录 一归并排序介绍&#xff1a; 二归并排序递归版本&#xff1a; 2.1递归思路&#xff1a; 2.2递归代码实现&#xff1a; 三归并排序非递归版本&#xff1a; 3.1非递归思路&#xff1a; 3.2非递归代码实现&#xff1a; 四归并排序性能分析&#xff1a; 欢迎大佬&#…