LuaJIT Garbage Collector Algorithms
Explain
本篇文章是对Make Pall发表wili内容《LuaJIT 3.0 new Garbage Collector》的翻译和扩展,因为原文是对LuaJIT 2.x GC重要功能的简介和对LuaJIT 3.0 new GC的工作计划,所以它并不是系统性介绍GC的文章。希望以后能有精力系统性的对LuaJIT 2.x GC做个总结。
到目前(2025-1-17)为止,LuaJIT 3.0尚未发布。看Make列的3.0 plan,其中优化了很多功能,非常值得期待。但他也说了,3.0有可能永远不会发布,这将是非常遗憾的一件事情。
一、Two-Color Mark & Sweep
Two-Color Mark & Sweep 是标记-清除算法的简化版本,使用两种颜色(白色和黑色)来表示对象的状态:
- 白色对象:表示未被访问的对象,默认情况下所有新分配的对象都是白色。如果一个对象在垃圾回收周期中结束时仍然是白色,说明它是不可达的,可以被回收。
- 黑色对象:表示已被标记为可达的对象。黑色对象不会被清除,并会在清除阶段颜色翻转为白色以便参与下一个 GC 周期。
1.1 GC流程
标记阶段(Mark Phase)从 GC 根(例如,主线程,全局变量等)开始,迭代遍历所有可达(live)对象,并将它们标记为黑色。待标记完成,没有被标记为黑色的对象都被视为无法访问,即死对象。
清除阶段(Sweep Phase)遍历所有内存中的对象:如果对象为白色,则认为其是死对象,将其释放;如果对象为黑色,则认为其可达,将颜色翻转为白色,准备参与下一次GC。
1.2 主要缺点
该算法的主要缺点是非增量式(non-incremental),整个垃圾回收过程必须一次性完成,程序代码(mutator,指运行中的程序)无法与垃圾回收器并行执行。即回收操作是原子性的,需要完全暂停程序运行,这种暂停称为 Stop-the-world(STW),会导致程序响应延迟,特别是当内存中有大量对象时,暂停时间可能很长。
这种回收方式不适合实时系统或对响应时间要求高的场景,例如游戏或用户界面。
1.3 优化思路
为了提升效率和降低开销,算法中可以引入一些优化,例如:
- 交换颜色的意义:在每次垃圾回收结束后,反转白色和黑色的定义。例如,将“黑色”定义为“未访问”,将“白色”定义为“可达”。这样可以避免在清除阶段对黑色对象的颜色翻转操作,减少额外的步骤。
- 增量式改进:尽管基础算法是非增量式的,但可以通过引入写屏障(Write Barrier)等机制改进为增量式标记。
1.4 应用实例
Lua 5.0 使用了 Two-Color Mark & Sweep 算法,具有以下特点:
- 对象存储结构:所有对象都存储在一个链表中。这种设计的优点是方便遍历内存中的所有对象,缺点是访问速度较慢。
- 标记列表(Mark List):在标记阶段,将需要遍历的对象放入一个独立的标记列表。这样可以加速标记阶段中对对象的处理,同时避免重复标记。
- 内存回收效率:Lua 5.0 的 GC 虽然简单,但由于设计目标是轻量级脚本语言,这种算法在小型脚本的场景中表现较好。
二、Tri-Color Incremental Mark & Sweep
Two-Color Mark & Sweep是 全停顿(Stop-the-world,STW) 的算法,会导致程序在垃圾回收时暂停。为了减少暂停时间,增量式垃圾回收 (Incremental GC)被提出, Tri-Color Marking则是其一种常用的技术。
Tri-Color Incremental是 Lua 5.1/5.2 和 LuaJIT 1.x/2.x 使用的 GC 算法,它是 Lua 5.0 链表算法的增强版。
Tri-Color Incremental Mark & Sweep 用三种颜色(白色、灰色、黑色)来区分对象的状态,三种颜色的定义如下:
- 白色(White):表示未访问的对象。在标记阶段开始时,所有的对象都被标记为白色。如果某个对象在整个标记阶段结束后仍然是白色,则说明该对象是不可达的垃圾,可以被回收。
- 灰色(Gray):表示已被标记,但未处理其引用对象的对象。意味着当前对象是可达的,但它可能引用其他未处理的对象。
- 黑色(Black):表示已被标记并且其引用对象也被处理完毕的对象。意味着该对象和它的引用对象都是可达的,无需再次处理。
2.1 GC流程
任何时刻新分配的对象都被标记为白色。
标记阶段,垃圾回收器从GC根(GCroots)开始,遇到一个可达的对象,将其颜色从白色变为灰色,并将其加入灰色栈(graystack,或重新链入灰色列表)。灰色栈中的对象会被逐一迭代处理,每次从栈中移除一个灰色对象,遍历灰色对象的所有引用,将其引用的对象标记为灰色,并将灰色对象加入灰色栈中。一个对象的所有引用遍历完成后,将其颜色会灰色变为黑色。
清除阶段与前面提到的Two-Color算法类似。遍历所有内存中的对象:如果对象为白色,则认为其是死对象,将其释放;如果对象为黑色,则认为其可达,将颜色翻转为白色,准备参与下一次GC。
2.2 增量式(Incremental)
为了避免一次性完成垃圾回收而导致程序长时间暂停,Tri-Color 标记算法可以增量执行。垃圾回收器采用分段标记,一次只处理少量灰色对象,然后将控制权交还给应用程序(mutator)。
这种方式将垃圾回收暂停分散为许多短间隔,特别适合对交互性要求高的场景(例如游戏或互联网服务器)。
增量式GC存在黑色对象引用白色对象
的问题。在增量过程中,mutator可能在回收器工作时,创建一个新的标记为白色的对象,并将白色对象(未处理)存储到一个黑色对象(已处理)中。如果发生这种情况,这个白色对象不会被标记为可达对象,而是在清除阶段被错误地回收,即使它实际上可以从一个可达对象中访问到。
对于此问题的解决方法,是维护三色不变性(Tri-ColorInvariant),GC必须满足以下两个不变性之一:
- 强三色不变性(Strong Tri-Color Invariant):黑色对象不能直接引用白色对象。如果存在这种情况,白色对象可能会被错误地认为是不可达的,从而被误回收。
- 弱三色不变性(Weak Tri-Color Invariant):黑色对象可以直接引用白色对象,但要求该白色对象必须存在其他灰色对象对它的引用,或者它的可达链路上游存在灰色对象。
通过插入屏障(Insertion Barrier)机制来实现。当对象A引用对象B时,如果对象B是白色,则将其标记为灰色,从而避免黑色对象直接引用白色对象。
2.3 写屏障(Write Barrier)
如果mutator在增量执行中破坏了三色不变性(如添加了新的引用),需要通过写屏障(Write Barrier)来修复。
写屏障(Write Barrier)在每次写操作后检查是否违反了三色不变性,如果发现不变性被破坏,需要采取修复操作。有两种修复方式:
- 后向屏障(Backward Barrier):将黑色对象重新变为灰色,并将其重新加入灰色栈中,以便稍后重新处理。优点:对于需频繁写入(例如容器对象)的对象,可以减少对相同对象的后续屏障检查。
- 前向屏障(Forward Barrier):立即将白色对象标记为灰色,并将其加入灰色栈中。优点:可以推动垃圾回收向前运行,适用于只进行孤立写操作的对象。
Lua 5.1/5.2 和 LuaJIT 1.x/2.x对Tables使用后向屏障,所有其他可遍历对象使用前向屏障。
LuaJIT 2.x 通过只检查标记黑色的table(忽略存储对象的颜色)进一步优化了table的写屏障。这样检查速度更快,而且仍然安全:写屏障可能会更频繁地触发,但这没有坏处。而且这在实践中并不重要,因为 GC 周期进展非常快,中间有较长的暂停,所以对象很少是黑色的。而且,存储的对象通常都是白色的。
以下是Mike Pall对LuaJIT中写屏障的一些介绍:
写屏障只需检查存储到其中的对象的灰色位(gray bit)。这是一个非常快速的测试,并且只有在未设置灰色位时才会触发(这种情况很少见)。
如果触发了写屏障,白色对象将变为浅灰色(light-gray),黑色对象将变为深灰色(dark-gray),深灰色对象还会被推送到快速顺序存储缓冲区 (sequential store buffer,SSB) 上。
浅灰色对象不需要推送到 SSB,但这需要检查标记位。如果触发屏障的性能成为问题,则可以避免这种情况。可以改为对 SSB 溢出进行检查。当收集器暂停时,可以完全避免检查标记位,因为不可能有任何黑色对象。
2.4 重要优化
程序堆栈(Stacks)始终保持为灰色,并在清除阶段之前重新遍历。这样可以避免对堆栈插槽的写入使用写屏障(堆栈插槽是写入操作最频繁的地方)。
没有对子对象的引用的对象可以立即从白色变为黑色,而不需要经过灰色堆栈。
可以通过使用两个白色并在进入清除阶段之前在它们之间翻转来使清除阶段成为增量。需要保留具有“current”白色的对象。只有具有“other”白色的对象才应该被释放。
三、Quad-Color Optimized Incremental Mark & Sweep
四、Generational GC
相关文章:

LuaJIT Garbage Collector Algorithms
Explain 本篇文章是对Make Pall发表wili内容《LuaJIT 3.0 new Garbage Collector》的翻译和扩展,因为原文是对LuaJIT 2.x GC重要功能的简介和对LuaJIT 3.0 new GC的工作计划,所以它并不是系统性介绍GC的文章。希望以后能有精力系统性的对LuaJIT 2.x GC做…...
go采集注册表
package mainimport ("fmt""golang.org/x/sys/windows/registry""log""os""strconv""strings" )func USBSTOR_Enum() {// 打开注册表键keyPath : SYSTEM\CurrentControlSet\Services\USBSTOR\Enumk, err : regist…...
软件工程师欧以宁:引领无人机导航与物联网安全的技术革新
在科技日新月异的今天,软件工程师欧以宁凭借卓越的技术能力和前瞻性的创新思维,成为了无人机自主导航和物联网安全领域的佼佼者。作为一名深耕技术前沿的专家,欧以宁不仅推动了无人机导航技术的突破性进展,还为智能家居和物联网的安全架构提供了全新的解决方案。她的研究成果,以…...

从零开始:Gitee 仓库创建与 Git 配置指南
引言 Git 是一款广泛使用的版本控制工具,它能够帮助开发者在开发过程中高效地管理代码的版本。而 Gitee(码云)是国内知名的 Git 托管平台,它提供了强大的代码托管、团队协作和项目管理功能。如果你是 Git 和 Gitee 的新手&#x…...

浅谈计算机网络02 | SDN控制平面
计算机网络控制平面 一、现代计算机网络控制平面概述1.1 与数据平面、管理平面的关系1.2 控制平面的发展历程 二、控制平面的关键技术剖析2.1 网络层协议2.1.1 OSPF协议2.1.2 BGP协议 2.2 SDN控制平面技术2.2.1 SDN架构与原理2.2.2 OpenFlow协议2.2.3 SDN控制器 一、现代计算机…...

在 QNAP NAS中使用 Container Station 运行 Docker 的完整指南
QNAP 为用户提供了一个名为 Container Station 的应用,它在 QNAP NAS 上将 Docker 和 LXC 结合在一起,通过图形化界面,让用户更轻松地在 NAS 上管理容器。本文将带你一步步了解如何在 QNAP NAS 上安装和使用 Container Station,以…...

XML在线格式化 - 加菲工具
XML在线格式化 打开网站 加菲工具 选择“XML 在线格式化” 输入XML,点击左上角的“格式化”按钮 得到格式化后的结果...
大数据学习(34)-mapreduce详解
&&大数据学习&& 🔥系列专栏: 👑哲学语录: 承认自己的无知,乃是开启智慧的大门 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言📝支持一下博主哦ᾑ…...
代码合并冲突解决push不上去的问题
环境:【IntelliJ IDEA】 【Gerrit】 1、错误信息 代码合并,迭代1合并到迭代2,解决冲突后,依然push不上去,报错信息如下: remote: Processing changes: refs: 1 remote: Processing changes: refs…...

万字长文介绍ARINC 653,以及在综合模块化航空电子设备(IMA)中的作用
文章目录 一、引言二、ARINC 653背景三、整体系统架构四、应用/执行(APEX)接口五、ARINC 653 RTOS内部机制六、健康监测功能七、软件应用八、ARINC 653现状九、总结 一、引言 在现代航空领域,综合模块化航空电子设备(IMA…...
MySQL 与 Redis 数据一致性 2
1. 强一致还是最终一致?2. 先写 MySQL 还是先写Redis?case 1 3. 缓存(Redis)更新还是清除?更新策略更新策略会有数据不一致问题?数据不一致的概率与影响如果使用监听binlog更新数据还会出现数据不一致问题?binlog的消费问题 使用消息队列行不行?其他方案总结: 数据不一致…...
MySQL程序之:使用类似URI的字符串或键值对连接到服务器
本节介绍使用类似URI的连接字符串或键值对来指定如何为MySQLShell等客户端建立到MySQL服务器的连接。 以下MySQL客户端支持使用类似URI的连接字符串或键值对连接到MySQL服务器: MySQL Shell实现X DevAPI的MySQL连接器 本节记录了所有有效的类似URI的字符串和键值…...

Docker私有仓库管理工具Registry
Docker私有仓库管理工具Registry 1 介绍 Registry是私有Docker仓库管理工具,Registry没有可视化管理页面和完备的管理策略。可借助Harbor、docker-registry-browser完成可视化和管理。Harbor是由VMware开发的企业级Docker registry服务。docker-registry-browser是…...

若依前后端分离项目部署(使用docker)
文章目录 一、搭建后端1.1 搭建流程:1.2 后端零件:1.2.1 mysql容器创建:1.2.2 redis容器创建:1.2.3 Dockerfile内容:1.2.4 构建项目镜像:1.2.5 创建后端容器: 二、前端搭建:2.1 搭建流程&#x…...

Unity2021.3.13崩溃的一种情况
如果出现如下的报错,可能是软件冲突的原因。自己的原因是使用f.lux这款软件似乎和Unity相互冲突,出现下面报错。 错误信息如上图...

Temp123
MapDB:的持久化机制,以及源码分析和摘取 1、spark streaming--struct streaming 基于 时间间隔 攒批 2、kafka-connect-hdfs 控制 flush.size 和 interval.ms控制 攒批 - 完全自研 攒批机制 - 使用 embeded 版 https://lxblog.com/qianwen/share?shar…...

春秋杯-WEB
SSTI 可以看到主页那里有个登录测试之后为ssti {{4*4}} fenjing梭哈即可得到payload {{((g.pop.__globals__.__builtins__.__import__(os)).popen(cat flag)).read()}}file_copy 看到题目名字为file_copy, 当输入路径时会返回目标文件的大小, 通…...
JavaEE:多线程初阶
JavaEE:多线程初阶 一、线程的原理和进程与线程之间的关系1. 线程的原理线程的基本概念线程的生命周期线程的调度线程的并发与并行 2. 进程与线程的关系进程(Process)线程与进程的关系进程和线程的对比线程的优势线程的缺点 3. 总结 二、多线…...

Linux之文件系统前世今生(一)
Linux在线1 Linux在线2 一、 基本概念 1.1 块(Block) 在计算机存储之图解机械硬盘这篇文章中我们提到过,磁盘读写的最小单位是扇区,也就是 512 Byte;很明显,每次读写的效率非常低。 为了提高IO效率&…...

当设置dialog中有el-table时,并设置el-table区域的滚动,看到el-table中多了一条横线
问题:当设置dialog中有el-table时,并设置el-table区域的滚动,看到el-table中多了一条横线; 原因:el-table有一个before的伪元素作为表格的下边框下,初始的时候已设置,在滚动的时候并没有重新设置…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...

【JavaWeb】Docker项目部署
引言 之前学习了Linux操作系统的常见命令,在Linux上安装软件,以及如何在Linux上部署一个单体项目,大多数同学都会有相同的感受,那就是麻烦。 核心体现在三点: 命令太多了,记不住 软件安装包名字复杂&…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...