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

深入探究Lua的GC算法(下)-《Lua设计与实现》的更多相关文章

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

    对于内存的管理,是程序在应用的时候的必需知识点,<Lua设计与实现>中对Lua语言的GC原理做了一个详细的讲解,云风的blog也对其进行了详尽的讲解Lua GC 的源码剖析 系列 给出作者 ...

  2. 浅谈c#和lua的gc

    前提: 本文参考和借鉴相关博客,相关版权归其所有,我只是做一个归纳整理,所以本文没有任何版权 参考文献和书籍: CLR和.Net对象生存周期:   https://www.cnblogs.com/Wd ...

  3. 【腾讯Bugly干货分享】手游热更新方案xLua开源:Unity3D下Lua编程解决方案

    本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:http://mp.weixin.qq.com/s/2bY7A6ihK9IMcA0bOFyB-Q 导语 xL ...

  4. 手游热更新方案xLua开源:Unity3D下Lua编程解决方案

    C#下Lua编程支持 xLua为Unity. .Net. Mono等C#环境增加Lua脚本编程的能力,借助xLua,这些Lua代码可以方便的和C#相互调用. xLua的突破 xLua在功能.性能.易用 ...

  5. Cocos2d-x下Lua调用自定义C++类和函数的最佳实践[转]

    Cocos2d-x下Lua调用C++这事之所以看起来这么复杂.网上所有的文档都没讲清楚,是因为存在5个层面的知识点: 1.在纯C环境下,把C函数注册进Lua环境,理解Lua和C之间可以互相调用的本质 ...

  6. 【转】Cocos2d-x下Lua调用自定义C++类和函数的最佳实践

    转自:http://segmentfault.com/blog/hongliang/1190000000631630 关于cocos2d-x下Lua调用C++的文档看了不少,但没有一篇真正把这事给讲明 ...

  7. Win32下 Qt与Lua交互使用(一):配置Qt下Lua运行环境

    偶然间看到Lua这种脚本语言,有点兴趣,简单学习了一下. 发现Lua与C++之间可以实现非常强的交互性.Lua中可以使用C++中的函数,C++中也可以使用Lua中的函数.由此可以引发出很多奇思妙想了. ...

  8. Win32下 Qt与Lua交互使用:配置Qt下Lua运行环境

    Lua与C++之间可以实现非常强的交互性.Lua中可以使用C++中的函数,C++中也可以使用Lua中的函数.由此可以引发出很多奇思妙想了. 简单来说,Lua动态的特性补充了C++的功能.当然,也看你具 ...

  9. Learning Lua Programming (3) iMac下搭建Lua脚本最好的编码环境(代码补全,编译运行)

    这篇文章参考自http://blog.sina.com.cn/s/blog_991afe570101rdgf.html,十分感谢原作者的伟大创造,本人亲测可行. 这篇文章记录一下如何在MAC系统环境下 ...

随机推荐

  1. Mycat 分片规则详解--数据迁移及节点扩容

    使用的是 Mycat 提供的 dataMigrate 脚本进行对数据进行迁移和节点扩容,目前支持的 Mycat 是1.6 版本,由于 Mycat 是由 Java 编写的因此在做数据迁移及节点扩容时需要 ...

  2. centos-6.7 内核升级(转)

    本文转自http://www.linuser.com/thread-1622-1-1.html 默认centos-6.7 自带的内核版本: [root@testserver ~ ::]#uname - ...

  3. js和jquery实现显示隐藏

    (选择的重要性) 当点击同一个按钮的时候实现显示影藏 <a id="link" class="b-btn-four task-resolve add-sub-tas ...

  4. 解决Hystrix Dashboard 一直是Loading ...的情况

    Hystrix是什么 Hystrix 能使你的系统在出现依赖服务失效的时候,通过隔离系统所依赖的服务,防止服务级联失败,同时提供失败回退机制,更优雅地应对失效,并使你的系统能更快地从异常中恢复. Hy ...

  5. 【Java实现】栈和队列就是这么简单

    一.前言 上一篇已经讲过了链表[Java实现单向链表]了,它跟数组都是线性结构的基础,本文主要讲解线性结构的应用:栈和队列 如果写错的地方希望大家能够多多体谅并指正哦,如果有更好的理解的方式也希望能够 ...

  6. 漫谈Java IO之普通IO流与BIO服务器

    今天来复习一下基础IO,也就是最普通的IO. 网络IO的基本知识与概念 普通IO以及BIO服务器 NIO的使用与服务器Hello world Netty的使用与服务器Hello world 输入流与输 ...

  7. Alpha冲刺总结

    团队成员 陈家权 031502107 赖晓连 031502118 雷晶 031502119 林巧娜 031502125 庄加鑫 031502147 一.项目预期计划及现实进展 项目预期计划 现实进展 ...

  8. Linux下硬盘分区

    1  fdisk -l查看硬盘及分区信息 我的系统(Archlinux)下的命令效果如下: 由上面的图片可以得知该系统只挂载了1个硬盘,命名为sda,其有2个主分区,sda1和sda2,至于为什么这么 ...

  9. python 实现cm批量上传

    import requests import json import time import random url = 'http://cm.admin.xxxx.com/customer/aj_ad ...

  10. vue mint-ui 三级地址联动

    我也是第一次写这种地址联动的 刚开始的时候 我还以为直接用select来写 后来公司的ios告知并不是这样的 他说应该时这样的 于是第一想法 赶紧找插件吧 但是找了一会未果  就问了公司大神 他刚开始 ...