JVM的垃圾收集算法

1.算法的分类

1.1标记清除算法

第一步:标记(找出内存中需要回收的对象,并且把它们标记出来)

根据可达性算法,标记的是存活的对象,然后将其他的空间进行回收

第二步:清除(清除掉被标记需要回收的对象,释放出对应的内存空间)

1.1.2缺点:

标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

(1)标记和清除两个过程都比较耗时,效率不高

(2)会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

1.1.3算法过程:

1.1.4标记清除算法的衍生规则之分配(动态分区分配策略)

首次适应算法(Fisrt-fit)

就是在遍历空闲链表的时候,一旦发现有大小等于需要的大小之后,就立即把该块分配给对象,并立即返回。

缺点:

首次GC后,找到了一个大小合适的空闲空间,直接将该对象放入,导致后面的没有遍历,后面的碎片化和空闲极大

最佳适应算法(Best-fit)

就是在遍历空闲链表的时候,返回刚好等于需要大小的块

缺点:

需要遍历全表

最差适应算法(Worst-fit)

就是在遍历空闲链表的时候,找出空闲链表中最大的分块,将其分割给申请的对象,其目的就是使得分割后分块的最大化,以便下次好分配,不过这种分配算法很容易产生很多很小的分块,这些分块也不能被使用 

缺点:

找到最大的直接放入,如果找到的空闲块有5个,但是申请的对象只有4个空间块,那就会空出来一个,导致内存碎片化严重,如果找到的空闲块有5个,但是申请的对象却有6个空间块,那就会报内存溢出

1.2标记复制算法

1.2.1标记复制算法过程

将内存划分为两块相等的区域,每次只使用其中一块。 当其中一块内存使用完了,就将还存活的对象复制到另外一块上面,然后把已经使用过的内存空间一次清除掉。

1.2.2缺点 

内存的利用只有一半

1.3标记整理(压缩)算法

标记整理算法严格意义应该叫做标记清除整理算法或者标记清除压缩算法

因为他的本质就是在标记清除的基础在进行再整理

 

 1.3.1标记整理(压缩)算法衍生算法

 1.3.1.1随机整理

对象的移动方式和它们初始的对象排列及引用关系无关

原本的内存布局3-4是连续的

整理后由于1已经没有了4补上来导致内存不连续

任意顺序整理实现简单,且执行速度快,但任意顺序可能会将原本相邻的对象打乱到不同的高速缓存行或者是虚拟内存页中(理解为打乱到内存各个地方),会降低赋值器的局部性。 包括他只能处理固定大小的对象,一旦对象大小不固定,就会增加其他的逻辑。 

1.3.1.2线性整理

将具有关联关系的对象排列在一起

相关的对象会进行整理,整理成一块块小区域,无法避免内存碎片

将7、9有关联得对象放在一起,只会整理一个块有关联得对象,不会将所有有用的对象整理到一起,导致内存碎片很多

 1.3.1.3滑动整理

将对象“滑动”到堆的一端,从而“挤出”垃圾,可以保持对象在堆中原有的顺序

1.3.2几种典型的整理算法

1.3.2.1双指针回收算法:

实现简单且速度快,但会打乱对象的原有布局,属于随机整理

整理流程:

第一次遍历:移动位置但是并不更新标记

头指针找空闲的单元(可达的对象时非空的单元),尾指针向前找可达的,直到找到头指针的找到的空闲单元,也就是两个指针走到同一个单元上

 第二次遍历:更新标记

 一个指针向前移动,找大于下标4的对象,并更新GCroot的引用关系

缺点:

这种算法遇到内存大小不一的情况,就无法将尾端的对象直接拿到前面(假设后面的对象是前面对象大小的2倍,前面只空出来一个格子,这时就放不进去了) 

解决这个问题:

头指针记算一下当前空闲对象的空间,在往后走,直到找到可以放下后面要移动的对象

1.3.2.2Lisp2算法(滑动整理算法):

需要在对象头用一个额外的槽来保存迁移完的地址

整理前:他是一个三指针算法,并且可以处理不同大小的对象。但是需要三次遍历,并且由于对象大小不一样,所以需要额外的空间存储,而不是直接移动

第一次遍历:Free指针是为了留位置,而Scan对象是为了找存活对象

free的位置:free在第一个可达对象后进行移动

Scan找可达的对象,找到后进行标记,并记下使用的空间,并将这个值给到free指针,free在进行移动

如,Scan在0的位置记录空间是1,走到3的位置记录下空间是2,走到6的位置时记录下空间是1,那么Free指针的位置就是4,。也就是3的位置

 第二次遍历:更新对象地址

end指针只是为了标记尾端,让Scan指针直到走到尾了

第三次遍历:移动对象

 为什么要先修改对象地址,在移动对象

假设先移动对象,将6直接移动到3的位置这时就会发生对象覆盖的情况,由于指针信息是存在对象中的,备覆盖了这个对象就无法再更改引用关系了

1.3.2.3引线整理算法:(基本不用)

可以在不引入额外空间开销的情况下实现滑动整理,但需要2次遍历堆, 且遍历成本较高

1.3.2.4单次遍历算法:

滑动回收,实时计算出对象的转发地址而不需要额外的开销

单次遍历算法的重点在于提前记录我们需要转移的位置 关键词:偏移向量,标记向量以及内存索引号

开辟一块额外的空间并将内存划分成一块一块的,用于记录偏移向量(要移动的对象从哪到哪),标记向量(移动到什么位置)以及内存索引号(现在的位置)

第一次遍历将这些信息记录下来,第二次遍历进行位置移动

1.3.3总结:

所有现代的标记-整理回收器均使用滑动整理,它不会改变对象的相对顺序,也就不会影响赋值器的空间局部性。复制式回收器甚至可以通过改变对象布局的方式,将对象与其父节点或者兄弟节点排列的更近以提高赋值器的空间局部性

1.3.3.4限制:

整理算法的限制,如任意顺序算法只能处理单一大小的对象,或者针对大小不同的对象需要分批处理;整理过程需要2次或者3次遍历堆空间;对象头部可能需要一个额外的槽来保存迁移的信息。

2.分代收集理论 

当前主流商业 JVM 的垃圾收集器,大多数都遵循了 分代收集(Generational Collection)的理论进行设计,这里需要解释下,很多博客都会把分代收集当成一种具体的垃圾收集算法,其实并不是,分代收集只是一种理论,一套指导方针,一套符合大多数程序运行实际情况的经验法则,它建立在几个分代假说之上

2.1分代回收三大假说:

2.1.1弱分代假说:

绝大多数对象朝生夕死

这个对应Eden区,通过一次局部GC就可以回收绝大部分对象

2.1.2强分代假说:

活得越久的对象,也就是熬过很多次垃圾回收的对象是越来越难以消亡的

这个对于old区当对象年龄大于15时,就将其放入空间更大的老年区

2.1.3跨代引用假说

老年代引用了青年代里面的对象,或者青年代中的对象引用了老年代中的对象。

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

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

相关文章

阿里云oss存储文件上传功能实现(保姆级教程)

先登录: 点击进入控制台 点击左上角导航栏按钮 搜索oss,点击进入 进入之后点击立即开通oss按钮,开通之后点击下图立即创建,弹出创建Bucket 填上Bucket名称,读写权限改为公共读。其他不变点击确定创建,完成…

LVS+keepalived——高可用集群

lvskeepalived:高可用集群 keepalived为lvs应运而生的高可用服务。lvs的调度器无法做高可用,于是keepalived这个软件。实现的是调度器的高可用。但是:keepalived不是专门为lvs集群服务的,也可以做其他代理服务器的高可用。 lvs的…

Spring Boot要如何学习?【云驻共创】

Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化新 Spring 应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。我这里会分享一些学习Spring Boot的方法和干货,包括…

Python如何实现模板方法设计模式?什么是模板方法设计模式?Python 模板方法设计模式示例代码

什么是模板方法(Template Method)设计模式? 模板方法(Template Method)是一种行为型设计模式,它定义了一个算法的骨架,将一些步骤延迟到子类中实现。这种模式允许子类为一个算法的特定步骤提供…

【Flink】Process Function

目录 1、ProcessFunction解析 1.1 抽象方法.processElement() 1.2 非抽象方法.onTimer() 2、Flink中8个不同的处理函数 2.1 ProcessFunction 2.2 KeyedProcessFunction 2.3 ProcessWindowFunction 2.4 ProcessAllWindowFunction 2.5 CoProcessFunction 2.6 ProcessJo…

【Java系列】SpringBoot 集成MongoDB 详细介绍

目录 写在前面 一、步骤介绍 步骤 1: 添加 MongoDB 依赖 步骤 2: 配置 MongoDB 连接信息 步骤 3: 创建实体类 步骤 4: 创建 Repository 接口 步骤 5: 使用 Repository 进行操作 二、特殊处理 写在前面 在Spring Boot中集成MongoDB的过程相对简单,以下是一个…

Linux下使用宏定义判断系统架构和系统类型

文章目录 查看编译器当前支持的宏定义查找指定的宏不同架构不同系统 附录-编译器内部常用的一些宏定义宏定义实际应用使用宏定义判断系统架构使用宏定义判断系统类型 一般情况下在linux下做C/C方面的开发不需要太关注系统架构,当然如果涉及到不同架构下的适配问题&a…

Python---变量的作用域

变量作用域:指的是变量的作用范围(变量在哪里可用,在哪里不可用),主要分为两类:局部变量和全局变量。 定义在函数外部的变量就称之为全局变量; 定义在函数内部的变量就称之为局部变量。 # 定义…

基于 Eureka 的 Ribbon 负载均衡实现原理【SpringCloud 源码分析】

目录 一、前言 二、源码分析 三、负载均衡策略 一、前言 如下图,我们在 orderserver 中通过 restTemplate 向 usersever 发起 http 请求,在服务拉取的时候,主机名 localhost 是用服务名 userserver 代替的,那么该 url 是一个可…

Android Studio 引入Xui框架-简单应用

Android Studio Flamingo | 2022.2.1 Patch 2 Android 11开发、Gradle Version 8.0、 jdk17 源代码:GitHub - xuexiangjys/XUI: 💍A simple and elegant Android native UI framework, free your hands! (一个简洁而优雅的Android原生UI框架&#xff…

录屏软件自动开启录视频,是如何实现的?

工作要留痕,作为职场人的一项必备技能,因此许多人在做一些重要操作的时候,就会提前开启录屏软件,把操作的每一个步骤进行录制,以避免在出现问题的时候进行检查。当每天都需要在固定的时间点重复某项工作的时候&#xf…

【力扣】从零开始的动态规划

【力扣】从零开始的动态规划 文章目录 【力扣】从零开始的动态规划开头139. 单词拆分解题思路 45. 跳跃游戏 II解题思路 5. 最长回文子串解题思路 1143. 最长公共子序列解题思路 931. 下降路径最小和解题思路 开头 本力扣题解用5题来引出动态规划的解题步骤,用于本…

竞赛选题 目标检测-行人车辆检测流量计数

文章目录 前言1\. 目标检测概况1.1 什么是目标检测?1.2 发展阶段 2\. 行人检测2.1 行人检测简介2.2 行人检测技术难点2.3 行人检测实现效果2.4 关键代码-训练过程 最后 前言 🔥 优质竞赛项目系列,今天要分享的是 行人车辆目标检测计数系统 …

【计算机网络笔记】路由算法之距离向量路由算法

系列文章目录 什么是计算机网络? 什么是网络协议? 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能(1)——速率、带宽、延迟 计算机网络性能(2)…

DAY60 84.柱状图中最大的矩形

84.柱状图中最大的矩形 题目要求:给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。 求在该柱状图中,能够勾勒出来的矩形的最大面积。 思路 单调栈 本地单调栈的解法和接雨水的题目是遥相呼…

【docker】虚拟化和docker容器概念

基础了解 IAAS: 基础设施服务,(只提供基础设施,没有系统) **SAAS: ** 软件即服务,(提供基础设施和系统) PAAS: 平台即服务,(提供基…

《白帽子讲web安全》

第十四章 PHP安全 文件包含漏洞是“代码注入”的一种。“代码注入”这种攻击,其原理就是注入一段用户能控制的脚本或代码,并让服务器端执行。“代码注入”的典型代表就是文件包含(File Inclusion)。文件包含可能会出现在JSP、PHP…

时序预测 | Matlab实现HPO-ELM猎食者算法优化极限学习机的时间序列预测

时序预测 | Matlab实现HPO-ELM猎食者算法优化极限学习机的时间序列预测 目录 时序预测 | Matlab实现HPO-ELM猎食者算法优化极限学习机的时间序列预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现HPO-ELM猎食者算法优化极限学习机时间序列预测 1.data为数据集…

【C++ 学习 ㊴】- 详解 C++ 的 I/O 流

目录 一、C 的 I/O 流 二、C 的标准 I/O 流 三、C 的文件 I/O 流 一、C 的 I/O 流 C 语言有一套完成数据读写(I/O)的解决方案: 使用 scanf()、gets() 等函数从键盘读取数据,使用 printf()、puts() 等函数向屏幕输出数据&#…

②【Hash】Redis常用数据类型:Hash [使用手册]

个人简介:Java领域新星创作者;阿里云技术博主、星级博主、专家博主;正在Java学习的路上摸爬滚打,记录学习的过程~ 个人主页:.29.的博客 学习社区:进去逛一逛~ Redis Hash ②Redis Hash 操作命令汇总1. hset…