Lua gc 机制版本迭代过程简述

news2025/2/22 13:38:55

文章目录

    • 内存自动化管理的概念
    • Lua 中的 gc 对象
    • Lua 中内存分配和释放的底层接口
    • Lua 5.0 gc 算法
    • Lua 5.1 gc 算法
    • Lua 5.2 - Lua 5.4 gc 算法
    • 参考内容

内存自动化管理的概念

内存自动化管理是指在指定内存不再被需要时可以自动被释放。通常有两种方案来实现内存的自动化管理:

  • 引用计数 (reference count)

  • 垃圾回收 (garbage collection)

Lua 选择的是垃圾回收的方案。不选择引用计数的方式的主要原因是,在动态类型语言中,使用引用计数来管理内存,即使是在没有申请任何内存的情况下也会有额外的开销。这里的额外开销主要是 cpu 开销,例如你只是操作了已分配内存的数据,没有分配新的内存,你也需要更新引用计数。

Lua 中的 gc 对象

Lua 中的所有对象都接受自动管理:tables, userdata, functions, threads, and strings. 在 Lua 运行期间,所有的 Lua 对象都链接到一个内置链表中,以供垃圾回收器可以找到他们。

何时对象需要被回收:当对象不再能从根集(root set)中访问到。

根集包括 Lua 注册表(registry)和共享元表(share metatable):

  • Lua 注册表:

    • 全局表 _G

    • 主协程(lua 栈)

    • package.loaded (加载的 modules)

  • 共享元表:

    • 被其他对象设置为元表的 table

Lua 中内存分配和释放的底层接口

Lua 不直接操作内存,例如向系统申请一大块内存来进行更细致的管理,而是直接使用标准 c 库的内存接口,例如 malloc、free 和 realloc。这样在一方面的确是有不足,使得 Lua 的内存管理依赖具体操作系统环境的内存管理机制的性能好坏,但是另一方面,Lua 通常是和 c 或其他语言搭配使用,这样开发人员可以为应用使用一套分配机制,而不会导致在应用中存在两种分配机制,一种服务于 Lua,一种服务于另外的语言。

Lua 5.0 gc 算法

基础的标记 + 清扫:

  • 标记:从根集开始,遍历对象关联图,标记存活的对象。

  • 清扫:遍历链接所有 Lua 对象的内置链表,删除那些没有被标记的对象。

void luaC_collectgarbage (lua_State *L) {
    mark(L);
    luaC_sweep(L, 0);
    checkSizes(L);
    luaC_callGCTM(L);
}

收集器步子大小的影响:

  • 极端情况一:从不启动收集,在收集器上没有任何 cpu 开销,但是内存压力很大,只会上涨不会下降。

  • 极端情况二:始终在运行收集器,cpu 开销巨大,但是内存情况维持得很好。

  • 比较合适的设置:当内存增长到上一次垃圾回收后的内存的两倍大小时开始新的一轮回收。

主要的缺陷:

由于 gc 过程是一个连续的不可中断的过程,一旦开始 gc,应用程序必须等到一次完整 gc 执行完毕才可继续运行,这个等待时间对大多数 cpu 密集型应用是不可接受的,这也是 Lua 5.1 新的 gc 机制出现前 Lua 的应用场景并没有之后那么广泛的重要原因。

Lua 5.1 gc 算法

主要的改进:收集器可以增量式地跟应用程序交替运行。

三色标记回收算法 (Tri-color Collector):

  • 状态说明:

    • 每一个 Lua 对象都处于白色、灰色和黑色三种状态之一。

    • 不能访问到的对象被标记成白色。

    • 可以访问到但是没有遍历到的对象被标记成灰色。

    • 被遍历到的对象被标记成黑色。

  • 约束条件:

    • 在根集中的对象是黑色或者灰色。

    • 一个黑色对象不能指向一个白色对象。

    • 灰色对象的存在形成了白色对象和黑色对象之间的隔离线,如下图红线所示。

    • 收集器通过遍历灰色对象来推进工作,将他们转换成黑色,在这个过程中可能会创建新的灰色对象。

    • 当不再存在灰色对象时,收集器结束工作。

在这里插入图片描述

修改器(Mutator):从垃圾收集器的角度来看,应用程序就像一个修改器一样在不断地改变那些被收集器试图收集的数据,对收集器的工作造成干扰。

屏障(Barriers):向前它可以将白色对象转化成灰色对象,向后它可以将黑色对象转化成灰色对象。

启发式设计(heuristics):

  • 从黑色回退到灰色的对象暂存到一个分离出去的链表中,仅供在 atomic 阶段拿来遍历,这样可以避免出现 ping-pong 现象(反复横跳)。

  • 栈中对象保持为灰色,避免当往栈中写入的时候触发写屏障。

    • 栈中对象通常来说是比较少的,但是赋值操作又比较频繁,所以这样做来避免写操作触发屏障检查是有收益的,代价是在 atomic 阶段栈需要遍历栈中对象。
  • 对 table 进行赋值操作,会将黑色的 table 回退到灰色。

    • 试想如果不这么处理,在对黑色 table 进行多次赋值时(a[x] = y),赋值的对象 x, y 会被标记成黑色,即使可能在后续某次赋值时 y 被替换掉(a[x] = z),这样就产生了额外开销的标记工作,如果将黑色 table 回退成灰色就可以避免掉这类额外开销。
  • 设置元表的操作,Lua 5.4 中已经修改为当被设置元表的对象是黑色并且元表是白色的情况下,将元表颜色向前转换为灰色,这是因为元表通常会被分配给许多不同的对象,并且元表比其他对象更加稳定。

    • Lua 5.1 和 Lua 5.2 中是将黑色的 table 回退成灰色。

原子操作阶段(atomic):

  • 这是标记流程的最后一步。

  • 在这个阶段会遍历 “gray again” 链表和栈对象,这块对象的量级可以认为很小,所以该阶段在整个回收流程的占比很小,可以认为该阶段相比于整个回收流程来说进行地非常迅速。

  • 检查并清理弱表。

  • 分离出确定复活的对象,复活他们以及关联对象。

  • 再次检查并清理弱表。(有一些弱表复活了)

收集器步子大小控制参数:

  • 暂停时间:通过检测距离上次回收结束增长了多少内存来触发下一次回收启动。一般设置为固定值 “2”, 当内存增长到上次的两倍时开始新的一轮回收。调用 collectgarbage ([opt [, arg]]) 接口设置,opt = “setpause”,arg = 200 表示两倍内存阈值。

  • 回收倍率:控制以分配速度为基准的回收的相对速度,通过 collectgarbage ([opt [, arg]]) 接口设置,opt = “setstepmul”,arg = 200,最好不要设置为小于 100 的值,它会导致垃圾回收器推进的十分缓慢,甚至都无法完成一次完整的 gc。详情参考 Lua 5.2 manual 2.5 节

注意:

  • 增量式回收算法虽然缩短了每次暂停主程序运行的时间,但是它并没有减少收集器进行一次完整 gc 带来的开销,恰恰相反它的总开销是更高的。

Lua 5.2 - Lua 5.4 gc 算法

Lua 5.2 在 Lua 5.1 增量回收的基础上提出了一个实验性的 gc 模式,分代模式:

As an experimental feature in Lua 5.2, you can change the collector’s operation mode from incremental to generational. A generational collector assumes that most objects die young, and therefore it traverses only young (recently created) objects. This behavior can reduce the time used by the collector, but also increases memory usage (as old dead objects may accumulate). To mitigate this second problem, from time to time the generational collector performs a full collection. Remember that this is an experimental feature; you are welcome to try it, but check your gains.

Lua 5.4 对 Lua 5.2 中的分代模式进行了一些优化,并且完善了世代模式称为一种正式的 gc 机制:

The garbage collector (GC) in Lua can work in two modes: incremental and generational.

The default GC mode with the default parameters are adequate for most uses. However, programs that waste a large proportion of their time allocating and freeing memory can benefit from other settings. Keep in mind that the GC behavior is non-portable both across platforms and across different Lua releases; therefore, optimal settings are also non-portable.

You can change the GC mode and parameters by calling lua_gc in C or collectgarbage in Lua. You can also use these functions to control the collector directly (e.g., to stop and restart it).

分代模式的 gc 机制在不少脚本语言的 gc 机制中存在,例如 c#,它基于以下假设:

大多数对象在早期就死亡了,所以,收集器可以专注于回收比较年轻的对象。

当这个假设成立的时候,分代模式的 gc 总开销是小于增量式的。 假设不成立的典型情形是批处理程序。

简单介绍:

  • 所有对象被划分为年轻的和年老的。刚创建的对象都是年轻的。在 Lua 5.4 中,需要存活超过两个回收周期,对象才会变成年老的,而在 Lua 5.2 中,只需要存活超过一个回收周期。

  • 收集器进行频繁的次级回收(minor collection),只遍历和清理年轻的对象。

  • 这里简单对比下存活不同周期后变成年老对象的区别:

    • Lua 5.2 年轻对象存活一个周期后变成年老对象

      • 简单许多的代码实现。

      • 在一次回收周期结束后,所有存活的对象都变成年老的。

      • 接触列表(touched list)中的对象可以移除出来。

      • 对象在变老之前可能只存活了无穷小的时间间隔,如图:

      • 在这里插入图片描述

    • Lua 5.4 年轻对象存活两个周期后变成年老对象

      • 在一次回收周期结束后,一些对象变成老的,一些没有。

      • 接触列表(touched list)中的对象需要被正确调整以能正常进行下次回收。

      • 对象在变老之前至少需要存活一个完整的 gc 周期,如图:

      • 在这里插入图片描述

  • 约束条件:

    • 一个年老对象不能指向一个年轻对象。
  • 接触列表(touched list):

    • 如果检测到一个老对象正指向一个年轻的对象,这个老对象会被标记为接触者(touched)并且被放到一个特殊的列表中(touched list)。

    • 在两次回收周期之后,一个接触者对象会恢复到正常的年老状态,除非它又再次被接触(指向一个年轻对象)。

    • 在这里插入图片描述

选择哪个模式:

正如官方手册所讲,带有默认参数的默认GC模式适用于大多数用途。然而,浪费大量时间分配和释放内存的程序可以从其他设置中受益。请记住,GC行为是不可移植的,无论是跨平台还是跨不同的Lua版本;因此,最佳设置也是不可移植的。需要开发人员根据自己的应用特性和机器特性进行不断的调整和测试来寻求合适的解决方案。

参考内容

  • Lua 各版本手册
  • Roberto Ierusalimschy 演讲 ppt
  • Roberto Ierusalimschy 演讲 video

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

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

相关文章

FFmpeg时间戳

1. I帧/P帧/B帧 I帧:I帧(Intra-coded picture, 帧内编码帧,常称为关键帧)包含一幅完整的图像信息,属于帧内编码图像,不含运动矢量,在解码时不需要参考其他帧图像。因此在I帧图像处可以切换频道,而不会导致…

康托展开逆康托展开详解(原理+Java实现)

康托展开&逆康托展开详解 康托展开康托展开公式康托展开代码 逆康托展开逆康托展开具体过程尼康托展开代码逆康托的应用 使用场景 康托展开 康托展开是一个全排列到一个自然数的双射,常用于构建哈希表时的空间压缩。 康托展开的实质是计算当前排列在所有由小到大…

【ADS】ADS复制原理图或版图到另一个工程

直接Ctrl CCtrl V无法粘贴 可以先导入要复制的工程 加入工程,复制完后在勾掉工程

RuoYi-VUE : make sure to provide the “name“ option

前言 略 错误 错误原因 theme-picker 组件未被注册。 解决 src/App.vue代码恢复成若依的代码即可。&#xff08;PS&#xff1a;不知道代码被谁修改了&#xff09; 缺少这一段&#xff1a; <script> import ThemePicker from "/components/ThemePicker";…

基础IO与文件系统

全文目录 C语言的文件操作函数系统调用接口openwritereadclose Linux中一切皆文件文件描述符重定向 缓冲区为什么fflush能直接找到缓冲区进行刷新 文件系统 C语言的文件操作函数 参考文章&#xff1a; C语言文件操作【基础知识 顺序读写 文件版通讯录】C语言文件操作收尾【…

FPGA工程中eclipse软件常见的错误

错误一&#xff1a; Unresolved inclusion: "altera_avalon_uart_regs.h" Unresolved inclusion: "system.h"Description Resource Path Location Type Type alt_u8 could not be resolved hello_world.c /UART line 37 Semantic Error描述&#xff1a;这个…

【计算机网络 02】物理层基本概念 传输媒体 传输方式 编码与调制 信道极限容量 章节小结

第二章 -- 物理层 2.1 物理层基本概念2.2 物理层下的传输媒体2.3 传输方式2.4 编码与调制2.5 信道极限容量2.6 章节小结 2.1 物理层基本概念 2.2 物理层下的传输媒体 传输媒体也称为传输介质或传输媒介&#xff0c;他就是数据传输系统中在发送器和接收器之间的物理通路 传输媒…

统信UOS安装nginx及其所需部件

/usr/local 为Linux默认软件安装路径&#xff0c;类似于C:\Program Files。 因此在local路径下新建nginx文件夹安装nginx。 下载并安装nginx &#xff08;1&#xff09;进入nginx文件夹下&#xff0c;使用 wget 命令下载nginx资源包 命令&#xff1a;wget http://nginx.org/…

微服务——http客户端Feign

目录 Restemplate方式调用存在的问题 Feign的介绍 基于Feign远程调用 Feign自定义配置 修改日志方式一(基于配置文件) 修改日志方式二(基于java代码) Feign的性能优化 连接池使用方法 Feign_最佳实践分析 方式一: 方式二 实现Feign最佳实践(方式二) 两种解决方案 Re…

Kubernetes教程(三)---纯三层网络方案

来自&#xff1a;指月 https://www.lixueduan.com 原文&#xff1a;https://www.lixueduan.com/posts/kubernetes/02-cluster-network/ 由于 COPY 过来图片无法展示&#xff0c;建议跳转到原文查看 本文主要介绍了 Kubernetes 中的 Pure Layer 3 网络方案。其中的典型例子&…

msvcp120.dll丢失的解决方法,msvcp120.dll一键修复方法

最近我遇到了一个让我头疼的问题&#xff0c;那就是在使用某个软件时出现了msvcp120.dll文件缺失的错误。这个错误导致我无法正常运行该软件&#xff0c;给我的工作和生活带来了很大的困扰。 起初&#xff0c;我尝试了一些简单的解决方法&#xff0c;比如重新安装软件、重启电脑…

Appium+python自动化(十八)- - Monkey事件

操作事件简介 Monkey所执行的随机事件流中包含11大事件&#xff0c;分别是触摸事件、手势事件、二指缩放事件、轨迹事件、屏幕旋转事件、基本导航事件、主要导航事件、系统按键事件、启动Activity事件、键盘事件、其他类型事件。Monkey通过这11大事件来模拟用户的常规操作&…

机器学习 深度学习编程笔记

sigmoid函数 def sigmoid(x):return 1.0 / (1np.exp((-x)))定义最小平方和损失函数 loss torch.nn.MSELoss()线性回归编程 如果不加噪音就成了正常的线性函数了&#xff0c;所以要加噪音。 torch.normal(0, 0.01, y.shape)torch.normal(0, 0.01, y.shape)是一个用于生成服从…

Vue 复杂json数据在el-table表格中展示(el-table分割数据)

文章目录 前言问题背景实现复杂json数据在el-table表格展示el-table-column分割线el-table-column高度 前言 在做复杂的动态表单&#xff0c;实现业务动态变动&#xff0c;比如有一条需要动态添加的el-form-item中包含了多个输入框&#xff0c;并实现表单验证&#xff0c;但在…

智慧税务大厅业务办理vr模拟体验提升缴税效率和质量

目前的税务部门的办事大厅&#xff0c;承载着纳税人的各种税务事项的办理&#xff0c;业务量较大&#xff0c;特别是窗口工作人员&#xff0c;在税务办理的高峰期&#xff0c;经常会遇到人手不够的情况&#xff0c;如果能够将vr技术应用的税务办理的环节中&#xff0c;让使用者…

FPGA FIFO——IP核

文章目录 前言一、FIFO1、区别2、分类 二、单时钟&多时钟FIFO框图三、FIFO IP 核配置四、源码1、fifo_wr(写模块)2、fifo_rd(读模块)3、ip_fifo(顶层文件) 五、仿真1、仿真文件2、波形分析 六、SignalTap II在线验证七、总结八、参考资料 前言 环境&#xff1a; 1、Quartus…

python与深度学习(六):CNN和手写数字识别二

目录 1. 说明2. 手写数字识别的CNN模型测试2.1 导入相关库2.2 加载数据和模型2.3 设置保存图片的路径2.4 加载图片2.5 图片预处理2.6 对图片进行预测2.7 显示图片 3. 完整代码和显示结果4. 多张图片进行测试的完整代码以及结果 1. 说明 本篇文章是对上篇文章训练的模型进行测试…

5.5.tensorRT基础(2)-封装插件过程,并实现更容易的插件开发

目录 前言1. 插件封装2. 补充知识总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记。 本次课程学习 tensorRT 基础-封装插件过程&#xff0c…

5G的发展过程

目录 1.什么是5G 2.5G与4G的区别 3.5G的应用领域 4.5G给人类带来的福利 5.5G未来的发展趋势 1.什么是5G 5G技术是第五代移动通信技术&#xff0c;它是对之前的2G、3G和4G技术的升级和革新。5G技术具有更高的数据传输速度、更低的延迟和更大的网络容量&#xff0c;为人们提供…

Qt简单实现密码器控件

本文实例为大家分享了Qt自定义一个密码器控件的简单实现代码&#xff0c;供大家参考&#xff0c;具体内容如下 实现构思&#xff1a; 密码器的功能可以看成是计算器和登陆界面的组合&#xff0c;所以在实现功能的过程中借鉴了大神的计算器的实现代码和登陆界面实现的代码。 …