深入探究Lua的GC算法(下)-《Lua设计与实现》

摘要:
在上一篇文章《zblade:深入研究Lua的GC算法(第1部分)——“Lua设计与实现”》之后,让我们完成GC的具体后续操作。udata的GC调用调用fasttm_GC中的TM。
这篇文章让我们收尾GC的具体后续操作。转载请标明出处:http://www.cnblogs.com/zblade/
3、GC的扫描阶段 GCSpropagate
深入探究Lua的GC算法(下)-《Lua设计与实现》第1张
深入探究Lua的GC算法(下)-《Lua设计与实现》第2张
只要处于这个阶段,就会分2种情况执行,一个是propagatemark,一个是atomic,让我们分别看其实现过程。
首先看处于灰色链表中一直都有对象的情况,在这步操作当中,是可以分步操作的,整个GC的分步操作,就是在这一步操作中,在每次扫描后,都会返回本次扫描标记的对象的大小之和,再下一个分步执行的时候再继续执行,而一旦进入atomic函数中,就需要一次性的执行,不能再分步执行了。
来看propagatemark函数是如何实现的:
深入探究Lua的GC算法(下)-《Lua设计与实现》第3张
深入探究Lua的GC算法(下)-《Lua设计与实现》第4张
对于table,如果该表是weak表,则退回到灰色状态,否则遍历表的数组和散列表部分进行标记,详见traversetable函数;
对于func,traverseclosure主要对func中的upval进行标记;
对于thread, 则将其移植到grayagain中,放在atomic中进行处理;
对于proto,对其中的字符串、upvalue、局部变量等进行遍历标记;
注意,这儿没有处理stringudata类型数据,这是放在其他部分进行的,不需要进行相关的标记;
 
4、GC 扫描阶段的barrier操作
由于采用分步式增量扫描标记算法,所以会出现在分步操作过程中,新增加的对象与被扫描过的对象之间有引用关系的变化,未来确保黑色对象引用的对象中有白色对象,lua提供了两种操作设计:
1)标记过程向前走一步 luaC_barrierf
如果新建对象是白色,而它被一个黑色对象引用了,那么将这个新建对象颜色从白色变为灰色;
2)标记过程向后走一步 luaC_barrierback
类似于上,此时将引用的它的黑色对象的颜色从黑色变为灰色,使得其重新被扫描一次
深入探究Lua的GC算法(下)-《Lua设计与实现》第5张
深入探究Lua的GC算法(下)-《Lua设计与实现》第6张
(或许你看出截图颜色变了,是的,回家了,又是新的编辑器了~)
从define可以看出,只有table需要进行luaC_barrierback,这是由于table本身设计,就是一个table可能会对应N个key或者value,这样如果新增一个key/value,如果将其置为灰色,然后将其加入gray链表中,这样多个添加会带来较大的性能。
采用向后,就是将该table对象退回到gray状态,这样添加多个,其实质都是只改变该table一次,注意这个gray不是改为gray链中,而是将该table加入到grayagain链中,在扫描完gray链后再扫描grayagain链即可。参考源码即可:
深入探究Lua的GC算法(下)-《Lua设计与实现》第7张
深入探究Lua的GC算法(下)-《Lua设计与实现》第8张
对比向前比较简单了:直接调用reallymarkoject
深入探究Lua的GC算法(下)-《Lua设计与实现》第9张
 深入探究Lua的GC算法(下)-《Lua设计与实现》第10张
5、GC的atomic操作
当gray链表中对象都标记完成后,会执行一次atomic操作,注意这个操作是不能被打断的,所以叫原子操作,参考源码:
深入探究Lua的GC算法(下)-《Lua设计与实现》第11张
深入探究Lua的GC算法(下)-《Lua设计与实现》第12张
首先处理上一篇文章中提到的对open状态的upvalues,然后处理一次gray链表;
然后处理整个弱表,将lua_State指针指向meta表,然后处理一次gray链表
然后处理grayagain链表,类似于上
然后处理udata,其处理函数为luaC_separateudata:
深入探究Lua的GC算法(下)-《Lua设计与实现》第13张
深入探究Lua的GC算法(下)-《Lua设计与实现》第14张
注释很详细,注意放到tmudata链表中后,是在后续操作再集中处理一次;
处理完基本的几个数据后,atomic会把白色类型切换到下一个GC操作的白色类型,然后修改状态到回收阶段CGSsweepstring, 这儿对sweepstrgc进行了赋初值,是为了下面的字符串定位。
 
6、GC的回收阶段 GCSsweepstring/GCSsweep
首先进入的回收阶段是对字符串的处理
深入探究Lua的GC算法(下)-《Lua设计与实现》第15张
深入探究Lua的GC算法(下)-《Lua设计与实现》第16张
虽然是case,但是其实质是一个循环,每次取出散列表中的一个字符串链表,进行一次遍历回收,sweepwholelist最终会调用到sweeplist,等一下给出源码。
当处理完所有的字符串后,切换到GCSsweep状态:
深入探究Lua的GC算法(下)-《Lua设计与实现》第17张
深入探究Lua的GC算法(下)-《Lua设计与实现》第18张
关键操作是sweeplist,参看其源码:
深入探究Lua的GC算法(下)-《Lua设计与实现》第19张
代码中也对前面说的多色标记中的两种白色的作用做了讲解,otherwhite就是本次不可回收的白色,如果处理的对象的白色就是otherwhite,是不会被回收的
 
7、结束阶段 GCSfinalize
这是整个GC的最后阶段了,来看看其操作的源码:
深入探究Lua的GC算法(下)-《Lua设计与实现》第20张
深入探究Lua的GC算法(下)-《Lua设计与实现》第21张
首先处理,是否有前面提到的tmudata链表, 其操作函数为GCTM:
深入探究Lua的GC算法(下)-《Lua设计与实现》第22张
注意,udata本身有GC方法,未来确保其GC方法的调用,实在这次GC中调用G方法,但是这个udata本身,是在下一次的GC中才会被回收的。udata的GC调用则是在fasttm中调用TM_GC来实现。
初看也会迷糊怎么循环的,其实结合上面的case中的 if(g->tmudata)可以理解,为什么每次GCTM都会执行 g->tmudata的移动赋值操作。
 
最终万事大吉,本次GC流程走完,设置到GCSpause状态,等待下一次GC调用。
 
8、GC的进度控制
其实GC的调用,可以分为两种,一种是自动调用,一个是手动调用
自动调用函数: luaC_checkGC
深入探究Lua的GC算法(下)-《Lua设计与实现》第23张
一般不希望自动GC,可以采用setthreshold,将GCthreshold的值设置为非常大,这样不回自动触发GC
手动调用,则设置GC的相关参数 setthreshold:
深入探究Lua的GC算法(下)-《Lua设计与实现》第24张
深入探究Lua的GC算法(下)-《Lua设计与实现》第25张
estimate是对当前内存使用量的一个预估值,gcpause是一个百分比,通过lua_gc可以设置,另一个gc进度的参数是gcstepmul,其主要影响singlestep函数的调用次数,具体原因参看源码:
深入探究Lua的GC算法(下)-《Lua设计与实现》第26张
深入探究Lua的GC算法(下)-《Lua设计与实现》第27张
整个流程都在注释中讲解了,其中关键是lim的设置,然后不断的调用singlestep, 然后处理GC状态即可,注意setthreshold是设置的两次GC之间的时间间隔。由于修改了threshold,对于关闭自动GC的情况,需要再次重新设置关闭自动GC一次。
 
9、总结
对于lua的GC的原理的探究就到这儿,熟悉一门语言的GC流程后,同理去推导理解其他语言的GC会有很大帮助,同时也可以在平时使用lua的时候,对于GC的一些操作更加知其所以然。大家共勉!

 

 

免责声明:文章转载自《深入探究Lua的GC算法(下)-《Lua设计与实现》》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Lua中table的实现-《Lua设计与实现》Java并发编程-多线程下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

LUA可变长参数 ... 三个点

本文翻译自 LUA官方文档 When a function is called, the list of arguments is adjusted to the length of the list of parameters, unless the function is a vararg function, which is indicated by...

layui.js源码分析

/*! @Title: Layui @Description:经典模块化前端框架 @Site: www.layui.com @Author: 贤心 @License:MIT */ ;!function(win) { "use strict"; var Lay = function() { this.v...

Android 7.0 Gallery图库源码分析1

分析一个项目的源代码时,第一件事就是查看清单文件,找到程序入口,我们从Gallery2源码的清单文件中可以看到GalleryActivity是此应用的启动Activity。 1 <activity android:name="com.android.gallery3d.app.GalleryActivity" android:label="@stri...

python执行lua代码

楔子 下面我们来看看如何使用python来执行lua代码。如果了解lua的话,可能会感到器官,我们之前调用C、调用go,都是调用其编写的动态库。可lua是脚本语言啊,难道也可以写动态库吗?其实我们不是调用动态库,而是直接执行lua代码。 这时候可能又有人猜到了,python执行lua代码,本质上应该还是通过lua解释器来调用吧。答案不是的,因为python...

Cocos2d-x Lua 阅读Csv文件,使用数据更方便

在我的书或出售之前,我的源代码,有Csvshadow文件。 也许这是偏见。我与工作将是最长的轮廓Csv,所以,我会帮助不大喜欢它的游戏。 Csv文件,非常格式easy,也就是说,一个数据线,字段之间用逗号分隔,策划也能够方便地使用Excel进行编辑。 Csv格式的文件。解析起来也非常easy,所以自己动手写写非常快~(小若:我就喜欢拿来主义,你怎么着)...

约瑟夫生死游戏(单链表实现)

本周的作业还算挺好玩。。约瑟夫生死游戏嘛。 老师要抽签选择每个组对应的数据结构。结果宝宝抽到了单链表。。。。 一、项目简介       约瑟夫生者死者游戏的大意是:30个旅客同乘一条船,因为严重超载,加上风高浪大,危险万分;因此船长告诉乘客,只有将全船一半的旅客投入海中,其余人才能幸免遇难。无奈,大家只得同意这种办法,并议定30个人围成一圈,由第一个人开始...