最近遇到 lua 死循环的情况,就研究下如何找到死循环所在的代码,方便定位和解决问题。
首先,要找到出问题的协程(lua_State)。lua vm 实现时,每个协程都有自己独立的堆栈(stack),以及函数栈(CallInfo)。
所以,要先找到死循环的协程,再从这个协程函数栈找到代码。
怎么找到这个协程?
有两种办法:
方法1、 在死循环会执行到的 opcode ,加代码取得当前协程;
方法2、 遍历所有 gc 数据对象,找到当前正在执行的协程。
最近遇到 lua 死循环的情况,就研究下如何找到死循环所在的代码,方便定位和解决问题。
首先,要找到出问题的协程(lua_State)。lua vm 实现时,每个协程都有自己独立的堆栈(stack),以及函数栈(CallInfo)。
所以,要先找到死循环的协程,再从这个协程函数栈找到代码。
有两种办法:
方法1、 在死循环会执行到的 opcode ,加代码取得当前协程;
方法2、 遍历所有 gc 数据对象,找到当前正在执行的协程。
最近我一直在看lua gc,阶段性做一下总结。网上很多文章没讲明白,我也当弥补下这个问题。文章以我看的lua 5.3.6做分析。
5.0 及以前使用的是双色标记清除法,gc 过程会停止主程序执行,直到 gc 完成;
5.1 实现了增量式 gc,采用三色标记法,gc 过程分多步,与主程序交替执行;
5.2 实现了分代 gc,实际效果不理想;
5.3 移除了分代 gc;
5.4 重新实现了分代 gc
标记清除算法,就是遍历所有对象,将还在使用的对象打上标记,遍历完成后,没有标记的对象就是垃圾对象,要清理掉。
所以,系统至少需要记录两个数据集合,一个是所有的对象集合,一个是还在使用的对象集合。在 lua 中,还在使用的对象集合包括了全局变量、 栈中对象、处于激活状态的协程等。
继续阅读lua5.3 垃圾回收分析
为了缓解数据库压力,数据会缓存在lua table,满足频繁读写需求,再定时检查,发现数据变了则落地。
问题来了,lua table怎么检查数据变了?
答案很简单,使用 metatable,这里贴一个简单的例子。
-- db数据 db = {openid="openid_123", token="token_123"} -- 缓存 cache = {} setmetatable(cache, { __index = function(t, k) return db[k] end, __newindex = function(t, k, v) if k ~= "__dirty" then db.__dirty = true end db[k] = v end, __pairs = function(t, k) return next, db, k end, }) for k, v in pairs(cache) do print(k, v) end cache.__dirty = nil print("cache.__dirty", cache.__dirty) cache.token = "token_456" print("cache.__dirty", cache.__dirty)
执行结果如下:
> dofile("test.lua") token token_123 openid openid_123 cache.__dirty nil cache.__dirty true
问题到这里就结束了。
接下来,我们再提出一个问题,lua table如何检查子项为table的数据变了?
继续阅读lua table怎么检查数据变了
异常捕获是高级语言的一大特性,通过对异常的捕获和处理,可以有效提高系统的稳定性和健壮性。因为无论再怎样改进代码,都不可避免出现一些异常,例如文件io错误、网络错误、内存错误等等,就要求编码对错误进行捕获,同时打印日志以便开发人员跟进问题的处理。当然,lua也提供了接口用于捕获运行时异常。
lua有两个函数可用于捕获异常: pcall 和 xpcall,这两个函数很类似,都会在保护模式下执行函数,效果类似try-catch,可捕获并处理异常。
两个函数的原型如下:
pcall (func [, arg1, ···]) xpcall (func, errfunc [, arg1, ···])
项目使用skynet框架,这个框架主要用lua写逻辑,但缺乏对HTTPS支持,所以我利用一点时间写了lua模块,支持异步HTTPS请求,文章这里讲述HTTPS相关知识,如何接入openssl请求HTTPS数据,同时也分享了lua模块给大家参考。