JVM面试题解,垃圾回收之“分代回收理论”剖析

一、什么是分代回收

我们会把堆内存中的对象间隔一段时间做一次GC(即垃圾回收),但是堆内存很大一块,内存布局分为新生代和老年代、其对象的特点不一样,所以回收的策略也应该各不相同

对于“刚出生”的新对象,很多时候生命周期并不长,有的只是临时用一下,需要短期被GC的概率很高,多次GC周期后都留存下来的对象就是很难被回收的对象。根据这两类对象的特点,我们就分为新生代和老年代,并且采取不同的回收算法。

二、分代回收算法有哪些

复制算法

原始的复制算法(Copying)是这样的:

  • 1、将内存按容量划分为大小相等的两块,每次只使用其中的一块。
  • 2、当其中一块内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。

带来的好处是:

  • 1、实现简单,运行高效,
  • 2、每次都是对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只要按顺序分配内存即可

存在的弊端是:

  • 1、内存的使用率缩小为原来的一半。
  • 2、内存移动是必须实打实的移动(复制),所以对应的引用(直接指针)需要调整。

适用场景:
复制回收算法适合于新生代,因为大部分对象朝生夕死,那么复制过去的对象比较少,效率自然就高,另外一半的一次性清理是很快的。

但是像 hotspot 这样的虚拟机大都对原生的复制算法进行了改进,因为它对内存空间的利用率不高,而且专门研究表明,新生代中的对象 98% 是“朝生夕死”的,所以并不需要按照 1:1 的比例来划分内存空间,所以改进后的复制回收策略叫做: Appel 式回收。

  • 1、将新生代划分为一块较大的 Eden 区和两块较小的 Survivor 空间(你可以叫做 From 或者 To ) , HotSpot 虚拟机默认 Eden 和 Survivor 的大小比例是 8:1
  • 2、每次使用 Eden 和其中一块 Survivor ,当回收时,将 Eden 和 Survivor 中还存活着的对象一次性地复制到另外一块 Survivor 空间上,最后清理掉 Eden 和刚才用过的 Survivor 空间。

在这样的算法下

  • 1、每次新生代中可用内存空间为整个新生代容量的 90%(80%+10%),只有 10%的内存会被 “浪费”
  • 2、当然,98%的对象可回收只是一般场景下的数据,我们没有办法保证每次回收都只有不多于 10%的对象存活,当 Survivor 空间不够用时,需要依赖其他内存(老年代)进行分配担保( Handle Promotion )。

 标记-清除算法  

标记-清除(Mark-Sweep)算法分为“标记”和“清除”两个阶段:

  • 1、首先扫描所有对象,标记出需要回收的对象,
  • 2、在标记完成后扫描并回收所有被标记的对象,故需要两次扫描

该算法特点如下:

  • 1、回收效率略低,如果大部分对象是朝生夕死,那么回收效率降低,因为需要大量标记对象和回收对象,对比复制回收效率要低,所以该算法不适合新生代。
  • 2、它的主要问题是在标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾回收动作。
  • 3、标记清除算法适用于老年代。 

标记-整理算法

算法逻辑如下:

  • 1、首先标记出所有需要回收的对象,
  • 2、在标记完成后,后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,
  • 3、然后直接清理掉端边界以外的内存。

该算法特点:

  • 1、标记整理需要扫描两遍
  • 2、标记整理与标记清除算法的区别主要在于对象的移动。对象移动不单单会加重系统负担,同时需要全程暂停用户线程才能进行,同时所有引用对象的地方都需要更新(直接指针需要调整)。
  • 3、标记整理算法不会产生内存碎片,但是效率偏低。
  • 4、标记整理算法适用于老年代。

因此,老年代采用的标记整理算法与标记清除算法,各有优点,各有缺点。

三、什么是跨代引用,如何解决?

什么是跨代引用

        分代回收也并不是简单划分一下内存区域这么简单,因为对象不是孤立的,对象之间存在跨代引用,譬如:现在要在新生代进行回收,但新生代的对象极有可能被老年代对象所引用,那为了找到这些可能存活的对象,不得不在既定的 GC Roots 之外,再遍历整个老年代对象确保可达性分析结果的正确性。反过来回收老年代也是一样。这样无疑带来了性能负担。

如何解决跨代引用

跨代引用相对于同代引用来说仅仅占少数,正是因为只占少数,所以不应该为了为了这些少量的跨代引用而区扫描整个老年代,也不能浪费空间让每个对象都记录它是否存在跨代引用。

所以为了解决这个问题只需要在新生代建立一个全局的数据结构叫做:记忆集( Remembered Set ),这个结构把老年代划分成若干小块内存,并标识哪块内存存在跨代引用,后续新生代发生 gc 时,只有包含了跨代引用的小内存区域才会被加入到 GC Roots 进行扫描;

当然这种方法需要在对象改变引用关系的时候维护记忆集中数据的正确性。这种做法相比垃圾收集时扫描整个老年代来说仍然是划算的

四、记忆集Remmber Set有了解过吗?卡表是什么

前面讲到,为了解决跨代引用带来的问题,垃圾收集器在新生代建立了一个叫做:记忆集的数据结构存储老年代哪些区域存在跨代引用,以便在根节点扫描时将这些老年代区域加入 GC Roots 的扫描范围,这样避免将整个老年代都加入 GC Roots 的扫描范围。

当然跨代引用的问题并非只在回收新生代才有,回收老年代也是一样的,所以需要更进一步理解记忆集的原理和实现方式。

记忆集定义:是一种用于记录从非收集区域指向收集区域的指针集合的抽象数据结构。

记忆集的实现:最常见的实现方式是通过卡表( Card Table )的方式去实现,卡表最简单的形式是一个字节数组( hotspot ),如下:

CARD_TABLE[this address >> 9 ] = 0
  • 1、字节数组 CARD_TABLE 的每一个元素都对应着其标识的内存区域中一块特定大小的内存块,这个内存块被称作:卡页( Card Page ),卡页大小一般是2的N次幂, hotspot 中是2的9次幂(地址右移9位),即512字节。
  • 2、如果卡表标识的起始地址是:0x0000,那数组的0,1,2号元素,分别对应的地址范围是:0x0000~ox01ff,0x0200~0x03ff,0x0400~0x05ff
  • 3、一个卡页的内存中通常包含不止一个对象,只要卡页内存中有一个或多个对象的字段存在跨代引用指针,那就将卡表对应字节数组元素的值标识位1,称之为 Ditry ,没有则标识位0,垃圾收集器工作时只要筛查 CARD_TABLE 中为1的元素,就能轻易找到哪些卡页内存块中包含跨代引用,就把这些内存块加入到 GC Roots 的扫描范围内。

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

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

相关文章

“腾讯、钉钉、飞书” 会议开源平替,免费功能强大

在数字化时代,远程办公和线上协作越来越火。然而,市面上的视频会议工具要么贵得离谱,要么功能受限,甚至还有些在数据安全和隐私保护上让人不放心。 今天开源君给大家安利一个超棒的开源项目 - Jitsi Meet,这可是我在网…

CNN-GRU卷积门控循环单元时间序列预测(Matlab完整源码和数据)

CNN-GRU卷积门控循环单元时间序列预测(Matlab完整源码和数据) 目录 CNN-GRU卷积门控循环单元时间序列预测(Matlab完整源码和数据)预测效果基本介绍CNN-GRU卷积门控循环单元时间序列预测一、引言1.1、研究背景与意义1.2、研究现状1…

状态模式——C++实现

目录 1. 状态模式简介 2. 代码示例 3. 单例状态对象 4. 状态模式与策略模式的辨析 1. 状态模式简介 状态模式是一种行为型模式。 状态模式的定义:状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。 通俗的说就是一个对象…

大华相机DH-IPC-HFW3237M支持的ONVIF协议

使用libONVIF C库。 先发现相机。 配置 lib目录 包含 编译提示缺的文件&#xff0c;到libonvif里面拷贝过来。 改UDP端口 代码 使用msvc 2022的向导生成空项目&#xff0c;从项目的main示例拷贝过来。 CameraOnvif.h #pragma once#include <QObject> #include &l…

WIN11 UEFI漏洞被发现, 可以绕过安全启动机制

近日&#xff0c;一个新的UEFI漏洞被发现&#xff0c;可通过多个系统恢复工具传播&#xff0c;微软已经正式将该漏洞标记为追踪编号“CVE-2024-7344”。根据报告的说明&#xff0c;该漏洞能让攻击者绕过安全启动机制&#xff0c;并部署对操作系统隐形的引导工具包。 据TomsH…

Kyligence AI 数据智能体:首批亮相神州数码 DC·AI 生态创新中心!

近日&#xff0c;跬智信息&#xff08;Kyligence&#xff09;长期合作伙伴神州数码&#xff0c;其 DCAI 生态创新中心正式启幕。 作为首批生态伙伴&#xff0c;Kyligence AI 数据智能体也正式入驻&#xff0c;在这里首次亮相。 Kyligence 是国内最早推出 AI 用数产品的厂商&a…

GS论文阅读--Hard Gaussian Splatting

前言 本文也是对高斯点云的分布进行优化的&#xff0c;看&#xff01; 文章目录 前言1.背景介绍2.关键内容2.1 位置梯度驱动HGS2.2 渲染误差引导HGS 3.文章贡献 1.背景介绍 在训练过程中&#xff0c;它严重依赖于视图空间位置梯度的平均幅度来增长高斯以减少渲染损失。然而&…

消息队列篇--原理篇--Pulsar(Namespace,BookKeeper,类似Kafka甚至更好的消息队列)

Apache Pulusar是一个分布式、多租户、高性能的发布/订阅&#xff08;Pub/Sub&#xff09;消息系统&#xff0c;最初由Yahoo开发并开源。它结合了Kafka和传统消息队列的优点&#xff0c;提供高吞吐量、低延迟、强一致性和可扩展的消息传递能力&#xff0c;适用于大规模分布式系…

当 Facebook 窥探隐私:用户的数字权利如何捍卫?

随着社交平台的普及&#xff0c;Facebook 已经成为全球用户日常生活的一部分。然而&#xff0c;伴随而来的隐私问题也愈发严峻。近年来&#xff0c;Facebook 频频被曝出泄露用户数据、滥用个人信息等事件&#xff0c;令公众对其隐私保护措施产生质疑。在这个信息化时代&#xf…

OSCP - Proving Grounds - Quackerjack

主要知识点 端口转发 具体步骤 执行nmap扫描,开了好多端口&#xff0c;我先试验80和8081&#xff0c;看起来8081比较有趣 Nmap scan report for 192.168.51.57 Host is up (0.0011s latency). Not shown: 65527 filtered tcp ports (no-response) PORT STATE SERVICE …

Hive之加载csv格式数据到hive

场景&#xff1a; 今天接了一个需求&#xff0c;将测试环境的hive数据导入到正式环境中。但是不需要整个流程的迁移&#xff0c;只需要迁移ads表 解决方案&#xff1a; 拿到这个需求首先想到两个方案&#xff1a; 1、将数据通过insert into语句导出&#xff0c;然后运行脚本 …

PHP如何封装项目框架达到高可用、高性能、高并发

很多初创公司为了快速上线业务&#xff0c;开发时间由本来的6个月压缩到3个月甚至2个月。开发人员只能根据时间及业务需求去git上找现有的项目二次开发或者是一个空框架根据业务一点一点的去做&#xff0c;上述两种方案虽然也可以上线但是对于业务本身存在的问题也是很大的&…

探究 Facebook 隐私安全发展方向,未来走向何方?

随着社交媒体的普及&#xff0c;隐私和数据安全问题成为了全球关注的焦点。Facebook&#xff0c;作为全球最大的社交平台之一&#xff0c;其隐私安全问题尤其引人注目。近年来&#xff0c;随着用户数据泄露事件的不断发生&#xff0c;Facebook 不断调整其隐私政策&#xff0c;探…

【Linux】其他备选高级IO模型

其他高级 I/O 模型 以上基本介绍的都是同步IO相关知识点&#xff0c;即在同步I/O模型中&#xff0c;程序发起I/O操作后会等待I/O操作完成&#xff0c;即程序会被阻塞&#xff0c;直到I/O完成。整个I/O过程在同一个线程中进行&#xff0c;程序在等待期间不能执行其他任务。下面…

R语言学习笔记之开发环境配置

一、概要 整个安装过程及遇到的问题记录 操作步骤备注&#xff08;包含遇到的问题&#xff09;1下载安装R语言2下载安装RStudio3离线安装pacman提示需要安装Rtools4安装Rtoolspacman、tidyfst均离线安装完成5加载tidyfst报错 提示需要安装依赖&#xff0c;试错逐步下载并安装…

数据分析 six库

目录 起因 什么是six库 智能识别py2或3 ​编辑 起因 ModuleNotFoundError: No module named sklearn.externals.six sklearn.externals.six 模块在较新版本的 scikit-learn 中已经被移除。如果你在尝试使用这个模块时遇到了 ModuleNotFoundError: No module named sklear…

HTML5使用favicon.ico图标

目录 1. 使用favicon.ico图标 1. 使用favicon.ico图标 favicon.ico一般用于作为网站标志&#xff0c;它显示在浏览器的地址栏或者标签上 制作favicon图标 选择一个png转ico的在线网站&#xff0c;这里以https://www.bitbug.net/为例。上传图片&#xff0c;目标尺寸选择48x48&a…

Langchain+文心一言调用

import osfrom langchain_community.llms import QianfanLLMEndpointos.environ["QIANFAN_AK"] "" os.environ["QIANFAN_SK"] ""llm_wenxin QianfanLLMEndpoint()res llm_wenxin.invoke("中国国庆日是哪一天?") print(…

Linux系统下速通stm32的clion开发环境配置

陆陆续续搞这个已经很久了。 因为自己新电脑是linux系统无法使用keil&#xff0c;一开始想使用vscode里的eide但感觉不太好用&#xff1b;后面想直接使用cudeide但又不想妥协&#xff0c;想趁着这个机会把linux上的其他单片机开发配置也搞明白&#xff1b;而且非常想搞懂cmake…

Unity自学之旅05

Unity自学之旅05 Unity学习之旅⑤&#x1f4dd; AI基础与敌人行为&#x1f94a; AI导航理论知识&#xff08;基础&#xff09;开始实践 &#x1f383; 敌人游戏机制追踪玩家攻击玩家子弹碰撞完善游戏失败条件 &#x1f917; 总结归纳 Unity学习之旅⑤ &#x1f4dd; AI基础与敌…