【JVM】垃圾回收算法(一)

垃圾回收算法

Java程序在运行过程中会产生大量的对象,但是内存大小是有限的,如果光用而不释放,那内存迟早被耗尽。如C/C++程序,需要程序员手动释放内存,Java则不需要,是由垃圾回收期去自动回收。垃圾回收器回收内存至少需要做两件事情:标记垃圾、回收垃圾。于是诞生了很多算法

垃圾判断算法之引用计数算法

在这里插入图片描述

最简单的垃圾判断算法。在对象中添加一个属性用于标记对象被应用的次数,每多一个其他对象引用,计数+1,当引用失效时,计数-1,如果计数=0,表示没有其他对象引用,就可以被回收。这个算法无法解决循环依赖的问题。像Redis中就使用了这样的算法,Netty中的ByteBuffer也是如此,Python中。
在该算法中,没有其他对应引用A对象和B对象,但是AB对象之间存在着互相引用,以致于垃圾收集器无法回收

垃圾判断算法之可达性分析算法

在这里插入图片描述

通过一系列被称为"GC Roots"的根对象作为其实节点集,从这些节点开始,搜索所走过的路径称为引用链(Reference Chain),当一个对象到GC Roots没有任何引用链相连(用图论的话来说,就是从GC Roots到这个对象不可达)时,则证明此对象时不可用的。如图所示,绿色对象虽然互相有关联,但是他们到
GC Roots是不可达的,所以他们将会被判断为是可回收的对象

哪些对象可以作为GC Roots呢?在Java语言中,可作为GC Roots的对象包括下面几种:

  • 1.虚拟机栈(栈帧中的本地变量表)中引用的对象

  • 2.方法区中类静态属性引用的对象

  • 3.方法区中常量引用的对象

  • 4.本地方法栈中JNI(即一般说的Native方法)引用的对象

  • 1.所有Java线程当前活跃的栈帧里指向GC堆里的对象的引用;换句话说,当前所有正在被调用的方法的引用类型的参数/局部变量/临时值

  • 2.VM的一些静态数据结构里指向GC堆里的对象的引用,例如说Hotspot VM里的Universe里由很多这样的引用

  • 3.JNI handles,包括global handles和local handles

  • 4.所有当前被加载的Java类

  • 5.Java类的引用类型静态常量

  • 6.Java类的运行时常量池里的引用类型常量(String或Class类型)

  • 7.String常量池(StringTable)里的引用

内存池

在这里插入图片描述

Memory Pool
内存池,如果拿运行时数据区域类比的话 => 它就是JVM内存模型管理器
Memory Chunk
内存块 => 堆 方法区
Memory Cell
细胞 => 一个对象对应多个Cell
为什么要有内存池?
对象的频繁操作会涉及到用户态和内核态的切换。核心:避免频繁调用操作系统API去向操作系统分配内存、释放内存
技术是没有绝对的,只有优点的技术。解决了一些问题,又诞生了另一些问题。

在OS中,随着我们打开的进程越来越多,内存空间也变得越来越紧张,对于已经打开的内存,OS系统是不会回收的,那么OS是怎么做的呢?OS会进行类似LRU的操作,把不经常用的内存导入到硬盘空间,swap空间,但也不会无限导入,超过了swap空间,就会触发OS的OOM Killer机制。那么如果进程突然切换了,会触发缺页异常,如果在硬盘上,就导入到物理内存中,这也就是垃圾收集器的诞生背景,因为这块内存是JVM自己控制的,所以操作系统没法帮我们做,思维要严谨

MAC长时间不用,硬盘空间占用会非常多,把内存置换到物理硬盘上

垃圾回收算法

由于JVM要对自己管理的对象进行回收,于是就诞生了不同的垃圾回收算法.

标记-清除算法

在这里插入图片描述

最基础的收集算法是"标记-清除"(Mark-Sweep)算法,如同它的名字一样,算法分为"标记"和"清楚"两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象,之所以说它是最基础的收集算法,是因为后续的收集算法都是基于这种思路并对其不足进行改进而得到的。
它的主要不足有两个:

  • 1.效率问题,标记和清楚两个过程的效率都不高;
  • 2.空间问题,标记清楚之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作

复制算法

在这里插入图片描述

为了解决效率问题,一种称为"复制"(Copying)的收集算法出现了,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这样使得每次都是对整个半区进行回收,内存分配时也就不用考虑内存碎片等复杂情况,只要移动堆顶指针,按顺序分配内存即可,实现简单,运行高效。只是这种算法的代价是将内存缩小为原来的一般,未免太高了了一点。
现代的商业虚拟机都采用这种收集算法来回收新生代,IBM公司的专门研究表明,新生代的对象98%是"朝生夕死"的,所以并不需要按照1:1的比例来划分内存空间,而是将内存分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden和其中一块Survivor.最后清理掉Eden和刚才用过的Survivor空间。HoSpot虚拟机默认Eden和Survivor的大小比例是8:1,也就是每次新生代中可用内存空间为整个新生代容量的90%(80%+10%),只有10%的内存会被浪费.当然98%的对象可回收只是一般场景下的数据,我们没有办法保证每次回收都只有不多于10%的对象存活,当Survivor空间不够用时,需要依赖其他内存(这里指老年代)进行分配担保(Handle Promotion).
内存的分配担保机制就好比我们去银行借款,如果我们信誉很好,在98%的情况下东鞥按时偿还,于是银行可能会默认我们下一次也能按时按量地偿还贷款,只需要有一个担保人能保证如果我不能还款时,可以从他的账户扣钱,那银行就认为没有风险了。内存的分配担保也一样,如果另外一块Survivor空间没有足够空间存放上一次新生代收集下来的存活对象时,这些对象将直接通过分配担保机制进入老年代

标记-整理算法

在这里插入图片描述

复制收集算法在对象存活率较高时就要进行较多的复制操作,效率将会变低。更关键的时,如果不想浪费50%的空间,就需要有额外的空间进行分配担保,以应对被使用的内存中所有对象都100%存活的极端情况,所以在老年代一般不能直接选用这种算法。因为没有多余的内存区域为老年代做担保,即便有,仍然需要有一块区域考虑到不能担保的情况。
根据老年代的特点,有人提出了另外一种"标记-整理"(Mark-Compact)算法,标记过程仍然与"标记-清楚"算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界意外的内存。

缺点:内存整理是CPU密集型的,比较耗费CPU

内存整理涉及到(排序+合并),那么需要遍历碎片。

  • 1.在合并的时候排序
  • 2.先排序再合并

碎片会存在哪些情况

  • 1.有序
  • 2.无序

思路:做两次遍历(jvm也是这样做的)
向前排序一次,比我小的内存地址往前移动
向后排序一次,比我大的内存地址往后移动

移动的对象为什么还可以访问?

在这里插入图片描述

因为对象的引用不是写死的,而是动态计算出来的。

  • 1.静态存储 写死的,那么每轮GC都需要依赖中间数据结构来存储新地址,工作量会比较大
  • 2.动态计算, 动态地址是怎么计算的?

计算规则:

  • 1.找到内存块的起始位置 + 数据块的起始地址 * 8字节对齐(对应的Hotspot源码中是HeapWord这个结构)
    get_data() + get_start() * get_align_size()

eg:如图所示:
0 + 3 * 8 = 24

分代收集算法

当前商业虚拟机的垃圾收集都采用"分代收集"(Generational Collection)算法。这种算法并没有什么新的思想,只是根据对象存活周期的不同将内存划分为几块。一般是把Java分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。在新生代中,每次垃圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高、没有额外对他进行分配担保,就必须使用"标记-清除"或"标记-整理"算法来进行回收

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

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

相关文章

基于x86 平台opencv的图像采集和seetaface6的眼睛状态检测(睁眼,闭眼)功能

目录 一、概述二、环境要求2.1 硬件环境2.2 软件环境三、开发流程3.1 编写测试3.2 配置资源文件3.3 验证功能一、概述 本文档是针对x86 平台opencv的图像采集和seetaface6的眼睛状态检测(睁眼,闭眼)功能,opencv通过摄像头采集视频图像,将采集的视频图像送给seetaface6的眼睛…

挑选适合的项目协同软件?看看这10款

文章主要介绍了以下10款项目协同进度软件:1.PingCode;2.Worktile;3.万户OA;4.小步外勤;5.智办事;6.万里牛;7.轻流;8.Toggl Track;9.Trello;10.Todoist。 在如…

PHP概述-特点-应用领域-如何学习

老师建议注册使用百度文心一言;讯飞星火大模型-AI大语言模型-星火大模型-科大讯飞;Kimi.ai - 帮你看更大的世界 等人工智能工具软件的一个到两个,也可下载文心一言、讯飞星火、kimi等APP软件使用,对于我们在读的大二学生来说有什么…

哪款麦克风音质效果好?一文看懂无线领夹麦克风什么品牌好

说到无线领夹麦克风麦克风,可能有些朋友对这个名字感觉很陌生,但是对于自媒体创作者以及短视频up主而言,应该会更熟悉一些。因为一款好的麦克风是提升音质的关键,而无线领夹麦克风作为一种小巧方便的收音设备,近些年更…

Citrix ADC Release 13.1 Build 54.29 (nCore, VPX, SDX, CPX, BLX) - 混合多云应用交付控制器

Citrix ADC Release 13.1 Build 54.29 (nCore, VPX, SDX, CPX, BLX) - 混合多云应用交付控制器 Citrix ADC - 混合多云应用交付控制器 请访问原文链接:https://sysin.org/blog/citrix-adc-13/,查看最新版。原创作品,转载请保留出处。 作者…

spring boot(学习笔记第十九课)

spring boot(学习笔记第十九课) Spring boot的batch框架,以及Swagger3(OpenAPI)整合 学习内容: Spring boot的batch框架Spring boot的Swagger3(OpenAPI)整合 1. Spring boot batch框架 Spring Batch是什么 Spring Batch 是一个…

行为识别实战第二天——Yolov5+SlowFast+deepsort: Action Detection(PytorchVideo)

Yolov5SlowFastdeepsort 一、简介 YoloV5SlowFastDeepSort 是一个结合了目标检测、动作识别和目标跟踪技术的视频处理框架。这一集成系统利用了各自领域中的先进技术,为视频监控、体育分析、人机交互等应用提供了一种强大的解决方案。 1. 组件说明: Y…

51单片机最快能生成多高频率的方波?

前言 在嵌入式系统开发中,51 单片机作为一种非常非常非常经典,贯穿上下几十年的微控制器,被广泛应用于各种电子项目中。其中,生成特定频率的方波信号是一项常见的需求。 那么,51 单片机究竟能以多快的速度生成方波呢&…

26 colorchooser组件

Tkinter colorchooser 组件使用指南 Tkinter 的 colorchooser 组件提供了一个图形界面,用于选择颜色。它允许用户通过标准的颜色选择对话框来选择颜色,非常适合需要颜色选择功能的GUI应用程序。以下是对 colorchooser 组件的详细说明和一个使用案例。 …

UNI-APP 打包构建 APK

UNI-APP 打包构建 APK 前言一、WINDOWS(在线 - 纯命令版)依赖其他前置准备实现原理操作步骤 二、WINDOWS(离线 - Android Studio 版)依赖(首次构建需要联网安装依赖)其他前置准备实现原理操作步骤 三、WIND…

网络安全的历史

如今,网络安全几乎成为各大公司和利益相关者关注的焦点。但在早期,网络安全的概念非常模糊。 直到多年以后,由于网络攻击和危险实体威胁的频繁发生,网络安全的发展才受到重视。这些措施的发展成为了网络安全的演变。 网络安全起…

el-pagination 下拉条目数最后一个样式改成全部

2024.08.27今天我学习了如何把el-pagination的下拉条目数修改,效果如下: 我们需要把最后一条选择换成全部展示,其实传给后端的还是总的数量,只是换了一个content, 通过f12查看元素可以拿到.el-select-dropdown__item …

创建django项目时遇到的改项目名字问题

问题描述 今天在学习时遇到了一些问题,现记录一下。 今天我利用 ‘django-admin startproject 项目名字’命令创建了一个项目,并觉得当时项目名字没有命好,所以就随性的运行了 ’rename 旧项目名字 新项目名字‘这一命令。但是随后就出现…

使用idea快速创建springbootWeb项目(springboot+springWeb+mybatis-Plus)

idea快速创建springbootWeb项目 详细步骤如下 1)创建项目 2)选择springboot版本 3)添加web依赖 4)添加Thymeleaf 5)添加lombok依赖 然后点击create进入下一步 双击pom.xml文件 6)添加mybatis-plus依赖 …

C_03_函数学习

函数 优点: 降低代码耦合度降低代码冗余度提高代码复用率提高代码可读性 思想: 封装【包装】 声明: 语法: extern 函数名(形参列表);// 注意:此时 形参列表中变量名可以忽略不写;定义&#xff1…

47.【C语言】指针(重难点)(J)

目录 26.自制排序函数(★★) *分析 *代码 往期推荐 26.自制排序函数 *分析 之前在42.【C语言】冒泡排序写过一个排序函数&#xff0c;可以将此自制一个类似qsort的函数 画圈的地方是需要修改的 #include <stddef.h> void bubble_sort(void* base, size_t num,size_t w…

Flat Ads:全球金融应用的营销投放洞察

随着移动互联网的普及,金融应用在全球范围内迅速崛起。无论是移动银行、支付服务,还是理财工具,金融类应用已经成为现代生活中不可或缺的一部分。根据最新的行业报告,全球金融应用的下载量和用户活跃度在过去几年里持续增长,尤其是在新兴市场,用户对数字金融服务的需求不断攀升…

力扣top100-链表类题易错点总结-c++实现(更新中)

首先给一个我之前写的双指针在链表类题中的妙用的link&#xff1a;双指针在链表中的妙用 tip1 来自“合并两个有序链表” 题目链接戳这里 这道题注意的就是如果是要返回一个新链表的头结点&#xff0c;一定要新建一个头结点&#xff1a; ListNode* prehead new ListNode…

java框架第二课(Reflection反射机制)

一.关于反射 (1)使用场景介绍 平常我们写代码时&#xff0c;都是已知类名&#xff0c;类的属性&#xff0c;构造方法&#xff0c;其他方法等信息&#xff0c;然后根据类名new对象&#xff0c;这个过程称为正向操作(例如&#xff1a;有一个管理员类&#xff0c;有账号和密码属…

【SQL】三角形判断

目录 题目 分析 代码 题目 表: Triangle ------------------- | Column Name | Type | ------------------- | x | int | | y | int | | z | int | ------------------- 在 SQL 中&#xff0c;(x, y, z)是该表的主键列。 该表的每一行包…