【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的眼睛…

springboot项目中如何改变web服务的路径

背景: 之前是spring项目,增加了servlet,对应非访问路径如/defA/inner-invoke/operator。 现在改造成了springboot项目后,默认路径是/oprator 希望不改动原有controller代码,让路径能够增加前缀让外面能正常调用。 原…

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

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

【markdown 中的文字颜色设置】按色系分类

文本颜色分类 蓝绿色系:灰色系:蓝紫色系:粉色系:绿色系:橘棕色系:语法,以天蓝色为例: <font color=skyblue>我是文字</font>我是文字 或者 替换成对应的16进制 <font color=#87CEEB>同理</font>同理 接下来是按色系分类的颜色名 蓝绿色系: …

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

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

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

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

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 - 混合多云应用交付控制器 请访问原文链接&#xff1a;https://sysin.org/blog/citrix-adc-13/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者…

前端下载时,出现err::netERR_FAULT的报错

场景&#xff1a;文件下载时&#xff0c;前端通过axios请求后台接口&#xff0c;同时将文件的“半链接”传给该接口&#xff0c;此时后台会重定到文件下载的链接&#xff0c;如果文件过大时&#xff0c;部分浏览器则会出现上述报错&#xff0c;导致无法下载 解决方案&#xff…

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

spring boot(学习笔记第十九课) Spring boot的batch框架&#xff0c;以及Swagger3(OpenAPI)整合 学习内容&#xff1a; Spring boot的batch框架Spring boot的Swagger3&#xff08;OpenAPI&#xff09;整合 1. Spring boot batch框架 Spring Batch是什么 Spring Batch 是一个…

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

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

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

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

postgresql版本升级

从postgresql 12升级至postgresql 14。 同一大版本的小版本无需更新数据目录&#xff0c;直接更新程序目录&#xff0c;但是要注意重新编译安装插件。 个人建议大版本中的小版本更新至5以上再使用&#xff0c;例如发稿时最新稳定版为16.4&#xff0c;建议至16.5以后再考虑升级…

26 colorchooser组件

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

UNI-APP 打包构建 APK

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

【Java】Java 设计模式之工厂模式与策略模式

Java设计模式是软件工程中一系列被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结&#xff0c;它们代表了最佳的实践&#xff0c;帮助开发者解决在软件设计过程中遇到的各种问题。这些模式可以根据其用途分为三大类&#xff1a;创建型、结构型和行为型&#xff0…

网络安全的历史

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

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

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

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

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

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

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

java.util.Optional.or() .orElse(), .orElseGet()的区别

java.util.Optional 是 Java 8 引入的一个容器类&#xff0c;用于表示一个可能包含或不包含非空值的对象。它提供了多种方法来处理可能为空的对象&#xff0c;从而避免使用null值。 在 Optional 中&#xff0c;.or(), .orElse(), 和 .orElseGet() 都是用于处理可能为空的值的方…