Lua的垃圾回收机制详解

Lua 是一种轻量级的编程语言,广泛用于嵌入到其他应用程序中,尤其是在游戏开发领域。Lua 的内存管理机制采用了自动垃圾收集(Garbage Collection)的方法。以下是Lua内存管理的一些关键方面:

垃圾收集原理概述

Lua 使用的是标记-清除(Mark-and-Sweep)算法进行垃圾收集。这个过程分为两个阶段:

  • 标记(Mark)阶段:Lua 遍历所有活动对象(即那些仍然可以从根集合直接或间接访问的对象),并将它们标记为活动的。
  • 清除(Sweep)阶段:Lua 移除所有未被标记的对象,释放它们占用的内存。

内存分配

Lua 使用 mallocfree(C语言标准库函数)进行内存分配和释放。

内存泄漏

尽管 Lua 提供了自动垃圾收集,但内存泄露仍然可能发生,尤其是在使用复杂的数据结构和循环引用时。程序员需要注意正确管理对象的生命周期,使用弱引用表来帮助打破潜在的循环引用。

弱引用表

弱引用表,简称弱表,是一种特殊类型的表,其键值对中的键(key)和/或值(value)可以是弱引用。这意味着,如果一个对象只被弱表所引用,那么它不会被视为活跃对象,因此可以被垃圾收集器回收。

弱表的行为通过设置其元表(metatable)中的 __mode 字段来控制。__mode 字段可以有以下设置:

  • "k":如果设置为 "k",则表中的键是弱引用。这意味着,如果一个对象只作为键存在于表中,它可以被回收。
  • "v":如果设置为 "v",则表中的值是弱引用。这意味着,如果一个对象只作为值存在于表中,它可以被回收。
  • "kv""vk":在这种情况下,键和值都是弱引用。

弱表的使用示例

如果一个对象只被弱表引用,一旦程序的其他部分不再引用该对象,它就会成为垃圾收集的候选对象。

这种特性使弱表成为实现自动缓存机制的理想选择。在缓存场景中,您可能希望暂时存储一些数据以提高效率,但如果这些数据不再被需要,它们应该自动释放,以避免不必要地占用内存。

假设您正在开发一个应用程序,需要频繁地对某些对象进行昂贵的计算。为了提高效率,您决定缓存这些计算结果。但是,您不希望缓存永久占用内存,特别是当原始对象不再需要时。

以下是一个实现这种缓存机制的 Lua 代码示例:

-- 创建一个值为弱引用的表
local cache = setmetatable({}, { __mode = "v" })function expensiveComputation(obj)-- 执行一些昂贵的计算-- ...return result
endfunction getCachedResult(obj)-- 首先检查结果是否已经在缓存中local result = cache[obj]if not result then-- 如果不在缓存中,执行计算并将结果存储在缓存中result = expensiveComputation(obj)cache[obj] = resultend-- 返回缓存或新计算的结果return result
end-- 使用示例
local myObject = {}
local result = getCachedResult(myObject)-- 当 myObject 不再被其他地方引用时,它以及其对应的缓存结果将自动被垃圾收集器清除

在这个例子中,cache 是一个弱表,用于存储昂贵计算的结果。当一个对象(如 myObject)传递给 getCachedResult 函数时,该函数首先检查是否已经有缓存结果。如果没有,它将执行计算并将结果存储在 cache 中。

由于 cache 是一个弱引用表,所以一旦 myObject 不再被程序的其他部分引用,它和其对应的缓存结果将自动成为垃圾收集的候选,从而释放相关内存。这样,缓存仅在数据实际需要时占用内存,避免了长期持有不再需要的数据导致的内存泄露。

使用弱表打破循环引用

在 Lua 中,使用弱引用表可以有效地帮助打破循环引用,从而避免内存泄露。循环引用发生在两个或多个对象互相持有对方的引用,导致它们都无法被垃圾收集器回收。弱引用表是一种特殊的表,其中的引用不会阻止垃圾收集器回收引用的对象。

假设我们有两个对象,A 和 B,它们互相持有对方的引用。这就形成了一个循环引用。

local A = {}
local B = {}A.other = B
B.other = A

在上面的代码中,A 持有对 B 的引用,B 也持有对 A 的引用。如果不采取措施,这将导致 A 和 B 都无法被垃圾收集器回收。

为了解决这个问题,我们可以使用弱引用表。我们将其中一个对象(比如 B)放入一个弱引用表中。

local A = {}
local weakTable = setmetatable({}, {__mode = "v"}) -- 创建一个值为弱引用的表local B = {}
weakTable[1] = B -- 把 B 存储在弱引用表中A.other = weakTable[1]
B.other = A

在这个例子中,B 存储在一个值为弱引用的表 weakTable 中。这意味着 weakTable 对 B 的引用不会阻止 B 被垃圾收集器回收。一旦外部对 B 的所有强引用(如直接引用)都消失,B 将可以被垃圾收集器回收,尽管 A 通过 weakTable 间接引用它。这样,我们就打破了循环引用,避免了内存泄露。

增量收集策略

在 Lua 中,垃圾回收器的增量收集(Incremental Collection)策略是为了减少垃圾收集过程对程序执行的干扰。传统的垃圾收集(如完全标记-清除或停止-复制算法)可能会在收集过程中暂停整个程序,尤其是在处理大量数据时,这种暂停会导致明显的性能问题。

增量收集的工作原理

增量垃圾收集通过将垃圾收集过程分解为多个小步骤来工作,而不是一次性完成所有工作。这些小步骤在程序的正常执行过程中逐渐完成,从而避免了长时间的程序暂停。这对于需要高响应性的应用程序,如游戏或实时系统,尤其重要。

Lua 的垃圾收集器主要通过以下步骤实现增量收集:

  1. 标记阶段的分解:在标记阶段,垃圾收集器逐渐标记活动对象。而不是一次性遍历所有对象。在每次程序的小暂停期间,它只标记一部分对象,然后让程序继续执行。

  2. 可调整的收集频率:Lua 允许调整垃圾收集器的工作频率。通过调整,可以控制垃圾收集器在程序执行中占用的比例,从而平衡性能和内存使用。

  3. 清扫阶段的分解:在清扫阶段,垃圾收集器逐步释放未标记的对象。这个过程也是分步进行的,每次执行释放一小部分对象。

调整和控制

Lua 提供了API(如 collectgarbage 函数)来调整垃圾收集器的行为,包括触发完整的垃圾收集循环、设置垃圾收集器的步进大小等。这些控制手段允许开发者根据具体应用的需要定制垃圾收集器的行为,优化性能和内存使用。

三色垃圾回收

三色垃圾回收是一种在增量收集中使用的标记策略。它通过将对象标记为三种颜色(白色、灰色、黑色)来追踪垃圾收集过程中的对象状态。这种方法允许垃圾回收器在程序的正常运行过程中逐步执行标记和清除操作。

三色标记法的原理

  1. 灰色(Gray):

    • 表示对象已经被标记,但是其引用的对象还没有被完全检查。
    • 灰色对象可能引用白色对象,所以不能直接清除。
  2. 白色(White):

    • 表示对象尚未被标记。
    • 白色对象可能是垃圾,因为没有灰色或黑色对象引用它们。
  3. 黑色(Black):

    • 表示对象已被标记,并且该对象引用的所有对象也都已经被检查。
    • 黑色对象不会引用任何白色对象,所以可以被安全清除。

三色垃圾回收的过程

在增量垃圾收集过程中,Lua 使用三色标记法来保证在整个回收过程中保持一致性。过程如下:

  1. 初始阶段:

    • 所有对象最初都是白色。
    • 当垃圾收集开始时,从根集合(如全局变量、活跃的函数调用栈等)出发,将可达对象标记为灰色。
  2. 标记阶段:

    • 将灰色对象转变为黑色,同时将它们直接引用的对象(如果是白色)标记为灰色。
    • 这个过程逐步进行,直到没有更多的灰色对象为止。
  3. 清扫阶段:

    • 所有剩余的白色对象都被视为垃圾并被清除。
    • 然后,收集器准备下一次收集,通常是通过将所有黑色对象转变为白色来实现。

分代垃圾收集

Lua 5.4 引入了分代垃圾收集(Generational Garbage Collection)机制,这是对其标准标记-清除(Mark-and-Sweep)垃圾回收算法的一个重要优化。分代垃圾收集基于这样一个观察:对象的生存时间往往有很大的差异,大多数对象在创建后不久就不再被使用(成为垃圾),而一些对象则可能存活得更久。

分代垃圾收集的基本原理

分代收集的基本理念是将对象分为几个“代”(generations),根据它们的存活时间对它们进行不同的处理。在 Lua 中,主要分为两代:

  1. 新生代(Young Generation):

    • 这一代包括最近创建的对象。
    • 新生代的对象经常进行垃圾收集,因为许多新创建的对象很快就不再被需要。
  2. 老年代(Old Generation):

    • 长时间存活的对象被移动到老年代。
    • 这些对象不会经常进行垃圾收集,因为一旦它们存活了一定时间,就很有可能会继续存活。

分代收集的过程

分代垃圾收集的过程大致如下:

  1. 新对象的分配:

    • 最初,所有新创建的对象都被放在新生代。
  2. 新生代的收集:

    • 新生代的垃圾收集频率相对较高。
    • 这是一种“次要垃圾收集”(Minor GC),通常只涉及新生代的对象。
  3. 晋升(Promotion):

    • 如果一个对象在新生代中存活足够长的时间(即在多次垃圾收集后仍然存活),它会被晋升到老年代。
    • 晋升是为了减少在这个对象上花费的垃圾收集努力,因为它很可能会继续存活。
  4. 老年代的收集:

    • 这是一种“主要垃圾收集”(Major GC),涉及整个内存(包括新生代和老年代)。
    • 老年代的垃圾收集频率比新生代低。

优势

  • 性能提升减少暂停时间

考虑因素

  • 分代收集增加了垃圾收集的复杂性,需要仔细平衡新生代和老年代的大小以及晋升策略,以实现最佳性能。
  • 在某些情况下,分代收集可能会导致内存使用效率稍微下降,因为一些长期存活的对象可能占据内存较长时间。

总的来说,分代垃圾收集是 Lua 在垃圾收集领域的一个重要进步,它通过智能地管理不同寿命的对象,提高了内存管理的效率和程序的整体性能。

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

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

相关文章

2020年AI怎么发展?听加州大学、谷歌、英伟达、IBM怎么说

来源:机器之心AI 领域最杰出的头脑如何总结 2019 年技术进展,又如何预测 2020 年发展趋势呢?本文介绍了 Soumith Chintala、Celeste Kidd、Jeff Dean 等人的观点。人工智能不是将要改变世界,而是正在改变世界。在新年以及新的十年…

ip打包后如何加入 xilinx_科普!插上USB设备后电脑是怎么识别的呢?

欢迎FPGA工程师加入官方微信技术群每次当插上鼠标或者U盘的时候,电脑是怎么知道是什么设备的呢?这里用到的就是枚举了。枚举,其实就是让HOST认识这个USB涉笔,并且为该设备准备资源,建立好主机和设备之间的数据传递机制…

两院院士评选2019年中国、世界十大科技进展新闻揭晓

来源:科学网由中国科学院、中国工程院主办,中国科学院学部工作局、中国工程院办公厅、中国科学报社承办,中国科学院院士和中国工程院院士投票评选的2019年中国十大科技进展新闻、世界十大科技进展新闻,1月11日在京揭晓。此项年度评…

android炫酷叼ui,XUI: 一个简洁而优雅的Android原生UI框架,解放你的双手!

XUI一个简洁而又优雅的Android原生UI框架,解放你的双手!还不赶紧点击使用说明文档,体验一下吧!涵盖绝大部分的UI组件:TextView、Button、EditText、ImageView、Spinner、Picker、Dialog、PopupWindow、ProgressBar、Lo…

笔记本电脑麦克风在哪里_定制款MacBook Pro? 13.3 体验 “旧”时代的 One Pecie_笔记本电脑...

2020-11-11 13:19:377点赞18收藏18评论9月28日 - 11月12日,参与#双11购物攻略#征稿活动,赢取苹果全家桶8888元超级锦鲤大奖!瓜分十万金币,值得买周边一次全攒齐!品类、品牌、场景、价格,快来分享你的购物心…

杨振宁眼中的物理学之美

来源:EETOP本文是当代物理学大师杨振宁教授1997年1月17日在香港中华科学与社会协进会与香港中文大学主办的演讲会上的演讲词,讲题原为“科学工作有没有风格”。转载于香港《二十一世纪》杂志1997 年 4 月号,总第40期;也收入杨振宁…

wechat电脑版_【学术工具】如何快速、免费翻译英文材料?原创·WeChat公号:本硕博资讯...

★学术工具英文材料免费翻译如何快速、免费翻译英文材料?原创WeChat公号:本硕博资讯分享一些亲测可用的资源,仅用于学术交流。建议大家试着自己翻译,提升英语水平。版权声明:如有侵权问题请通过邮箱或者公众号后台私信…

20155234 2016-2017-2 《Java程序设计》第5周学习总结

20155234 2016-2017-2 《Java程序设计》第5周学习总结 教材学习内容总结 Java中所有错误都会被打包为对象,运用try、catch,可以在错误发生时显示友好的错误信息。运用try、catch,还可以在捕捉处理错误之后,尝试恢复程序正常执行流…

harmonyos 编译打包生成app,鸿蒙(HarmonyOS)App开发入门(2)—运行HelloWorld

前言为确保HarmonyOS应用的完整性,HarmonyOS通过数字证书和授权文件来对应用进行管控,只有签名过的HAP(编译产物,后面章节详细讲述,本章主要讲证书申请到代码运行到真机)才允许安装到设备上进行运行(如果不带签名信息,…

【周末阅读】你不得不知道的10大AI赋能行业,你身边都能找到!

来源:青岛智能产业技术研究院智能产业 前沿高地【导读】AI正突破诸多技术瓶颈,在市政、交通、医疗、等行业横向渗透,逐步走入大众日常生活中。国务院印发的《新一代人工智能发展规划》中指出,2020年人工智能产业规模将超过1500亿元…

bindresult必须在哪个位置_管道疏通剂哪个牌子好 管道疏通机使用方法有哪些

平时大家不用的水或者一些物品,在处理的时候应该都会倒到下水道之中,而下水道确实具备着这一种效果,但很多时候,下水道往往会因为口比较小,而被一些物品所堵塞,这样一来,影响上其实会非常大&…

华为深度学习新模型DeepShift:移位和求反代替乘法,神经网络成本大降

来源:机器学习研究会订阅号【导读】深度学习模型,尤其是卷积神经网络的计算成本问题主要是由于卷积层和全连接层中大量进行乘法运算造成的。华为异构实验室的研究人员提出,用移位和求反运算代替乘法,可有效缓解计算成本过高的问题…

如何把竖排的数据变为横排_如何有效的自学日语自学的经验都在这里了

一.基础知识引入自学一门语言之前,先要了解这门语言的基本信息。从狭义上来说,语言是能够传达意义的声音,每个语种都由一定数量的声音构成。比如日语,日语普通话中的声音一共有104个。当这些声音对应成符号书写下来时&…

jquery获取html页面参数乱码,JS或Jquery获取浏览器URL的参数值 汉字值乱码 并转码...

1、获取url很简单,代码如下:window.location.href;2、jquery获取url参数比较复杂,要用到正则表达式,所以学好javascript正则式多么重要的事情首先看看单纯的通过javascript是如何来获取url中的某个参数://获取url中的参…

信阳农林技术学院经纬度_信阳无人机创业团队:让梦想在田野起飞

青春由磨砺而出彩,人生因奋斗而升华。在河南信阳,有这样一个年轻的创业团队,他们立志扎根农村做新型农民。他们在大学期间就钻研如何把无人机技术和现代农业生产相结合,并且运用到田间地头,在田野之上放飞青春梦想。一…

edge怎么开启沉浸式阅读_建安中艺光影秀|景区乐园开启沉浸式光影秀互动之旅...

随着时代的发展,文旅夜游的主旋律逐渐向声、光、电的科技和水、陆、空的视听体验靠近,越来越多的园林景点打造沉浸式光影互动投影秀,将历史人文与自然界的静谧纯粹相结合,利用沉浸式光影秀将园林景区中假山、悬崖、溶洞、峭壁、飞…

李德毅院士:自动驾驶与智能网联

来源:58车在电动化、智能化、网联化革命带动下,传统的汽车产业供应链正在重塑,中国电动汽车发展进入结构调整期。以“把握形势 聚焦转型 引领创新”为主题的2020中国电动汽车百人会论坛于1月10-12日在钓鱼台国宾馆隆重召开。秉持“传递权威信…

科技领域看不见的手如何影响企业未来命运

作者:刘锋“看不见的手”像幽灵一样盘踞在人类社会的发展过程中,时隐时现,在亚当斯密的《国富论》中,看不见的手推动了经济的发展;在达尔文的进化论中,看不见的手推动了生物的自然选择;同样在21…

电脑动态屏保_Mac待机也能看时间,你需要一款时钟屏保!

Mac待机也能看时间啦,时钟屏保软件就可以做到哦,今天就为大家分享几款,来看看有没有喜欢的!Mac待机时也能看时间(原文)​www.macz.com第一款:Word Clock 一起进入Word时钟的词云。 Word Clock M…

垂直居中——登录界面

弹性盒子垂直居中&#xff1a;body直接display&#xff1a;flex不行中间在来一层。 1 <!DOCTYPE html>2 <html>3 <head>4 <meta charset"utf-8">5 <link rel"stylesheet" href"https://cdn.static.runoob.com/libs/bootst…