快速掌握Lua 5.3 —— 调试库 (2)
2016-05-08 16:40
1461 查看
Q:如何调试”Closure”的”upvalue”信息?
A:--[[ debug.getupvalue(f, up) 返回函数("Closure")"f"的第"up"个"upvalue"的名字和值。 Lua按照"upvalues"在匿名函数中出现的顺序对其编号。如果指定的"up"索引越界,则返回"nil"。 以'('开头的变量名表示没有名字的变量(比如是循环控制用到的控制变量,或是去除了调试信息的代码块)。 debug.setupvalue(f, up, value) 与"debug.setupvalue()"的功能相对,将函数"f"("Closure")的第"up"个"upvalue"的值设置为"value"。 函数返回被设置的"upvalue"的名字。如果指定的"up"索引越界,则返回"nil"。 注:获取与设置"upvalue"与"Closure"是否被调用(是否在调用栈上)无关。]] -- "Closure"。 function newCounter () local n = 0 local k = 0 return function () k = n n = n + 1 return n end end counter = newCounter() print(counter()) print(counter()) -- 此时"k"是1,"n"是2。 local i = 1 repeat name, val = debug.getupvalue(counter, i) if name then print ("index", i, name, "=", val) -- 依次输出两个"upvalues"的名字和值。 if(name == "n") then debug.setupvalue (counter, 2, 10) -- 设置"n"的值为10。 end i = i + 1 end until not name -- 此时"n"的值被设置为10。 print(counter()) -- 在此调用后"n"的值被加1,变为11。 --[[ results: 1 2 index 1 k = 1 index 2 n = 2 11 ]] --[[ debug.upvaluejoin(f1, n1, f2, n2) 让"Closure""f1"的第"n1"个"upvalue"引用"Closure""f2"的第"n2"个"upvalue"。 debug.upvalueid(f, n) 返回指定"Closure""f"的第"n"个"upvalue"的标识符 (一个轻量用户数据,每个"upvalue"的标识符唯一)。 这个标识符可以让程序检查两个不同的"Closure"是否共享了相同的"upvalue(s)"。 ]] function newCounter() local n = 0 local k = 0 return function () k = n n = n + 1 return n end end counter = newCounter() function newCounter1() local n = 0 local k = 0 return function () k = n n = n + 1 return n end end counter1 = newCounter1() -- 每个"upvalue"都有自己独有的ID。 print(debug.upvalueid(counter, 1)) --> userdata: 00559300 print(debug.upvalueid(counter, 2)) --> userdata: 00559348 print(debug.upvalueid(counter1, 1)) --> userdata: 005593D8 print(debug.upvalueid(counter1, 2)) --> userdata: 00559420 -- 让"counter"的第一个"upvalue"引用"counter1"的第二个"upvalue"。 debug.upvaluejoin(counter, 1, counter1, 2) -- "counter"的第一个"upvalue"与"counter1"的第二个"upvalue"的ID相同。 print(debug.upvalueid(counter, 1)) --> userdata: 00559420 print(debug.upvalueid(counter, 2)) --> userdata: 00559348 print(debug.upvalueid(counter1, 1)) --> userdata: 005593D8 print(debug.upvalueid(counter1, 2)) --> userdata: 00559420
Q:如何追踪程序的运行?
A:--[[ debug.sethook([thread,] hook, mask [, count]) 将函数"hook"设置为线程"thread"的钩子函数。 "mask"决定钩子函数何时被触发,"count"决定何时额外的调用一次钩子函数。 "thread"默认为当前线程。"count"默认为0, 钩子函数将在每运行"count"条指令时额外的调用一次钩子函数,向钩子函数传递事件"count"。 "mask"可以指定为如下值的一个或多个: 'c': 每当Lua调用一个函数时,调用钩子函数,向钩子函数传递事件"call"或"tail call"; 'r': 每当Lua从一个函数内返回时,调用钩子函数,向钩子函数传递事件"return"; 'l': 每当Lua进入新的一行时,调用钩子函数,向钩子函数传递事件"line"。 当钩子函数被调用时,第一个参数是触发这次调用的事件。对于"line"事件,有第二个参数,为当前行号。 函数不传参,则为关闭钩子函数。]] debug.sethook(print, "crl") function foo() local a = 1 end local x = 1 foo() local y = 1 --[[ results: return nil line 5 line 3 line 7 line 8 call nil line 4 line 5 return nil line 9 return nil return nil ]] --[[ debug.gethook([thread]) 返回钩子函数的内存地址,钩子函数的掩码,"debug.sethook()"为钩子函数设置的"count"。]] debug.sethook(print, "l", 9) print(debug.gethook()) debug.sethook() -- 关闭钩子函数。 print(debug.gethook()) -- 没有钩子函数就什么都获取不到了。 --[[ results: line 2 function: 013D1A70 l 9 line 3 nil 0 ]]
Q:如何查看Lua的注册表信息?
A:--[[ debug.getregistry() 函数返回Lua的"registry"。]]
Q:如何创建一个程序分析器?
A:调式库除了用于调式以外还可以用于完成其他任务,这种常见的任务就是分析。对于一个实时的分析来说,最好使用C接口来完成。对于每一个钩子函数其使用的Lua调用代价太大,并且通常会导致测量的结果不准确。然而,对于计数分析来说,Lua可以很好的胜任。-- 一个记录程序中函数被调用次数的小型基本分析器。 local Counters = {} -- key-value: 函数-计数 local Names = {} -- key-value:函数-函数名 local function hook() local f = debug.getinfo(2, "f").func -- 获取被调用的函数本身。 if Counters[f] == nil then -- 如果是第一次被调用。 Counters[f] = 1 Names[f] = debug.getinfo(2, "Sn") -- 获取函数信息。 else -- 如果之前被记录过,这里只是增加其计数。 Counters[f] = Counters[f] + 1 end end local f = assert(load("print('Hello World!')")) debug.sethook(hook, "c") -- 当函数被调用时调用钩子函数。 f() debug.sethook() -- 关闭钩子函数。 -- 获取结果。 function getname(func) local n = Names[func] if n.what == "C" then -- 如果是C函数,只返回其名字。 return n.name end -- 如果不是C函数,返回"[file]:line"的形式。 local loc = string.format("[%s]:%s", n.short_src, n.linedefined) if n.namewhat ~= "" then -- 如果不是匿名函数,返回一个合理的名字,"[file]:line (name)"。 return string.format("%s (%s)", loc, n.name) else -- 否则只返回"[file]:line"的形式。 return string.format("%s", loc) end end for func, count in pairs(Counters) do print(getname(func), count) end --[[ results: Hello World! [[string "print('Hello World!')"]]:0 (f) 1 print 1 sethook 1 nil 1 <-- 这个不知道是什么函数。 ]]
附加:
1、在钩子函数内,你可以调用”debug.getinfo()”,指定栈级别为2, 来获得正在运行的函数的详细信息(”debug.getinfo()”的栈级别为0,钩子函数的栈级别为1)。2、一个打印文件名及行号的精致的追踪器,
function trace(event, line) local s = debug.getinfo(2).short_src print(s .. ":" .. line) end debug.sethook(trace, "l")
相关文章推荐
- 详解Lua中的表的概念及其相关操作方法
- Lua编程示例(二):面向对象、metatable对表进行扩展
- 把Lua编译进nginx步骤方法
- Lua脚本自动生成APK包
- Lua中的元表(metatable)、元方法(metamethod)详解
- Lua中的metatable介绍
- Lua中ipair和pair的区别
- Lua中的函数精讲笔记
- 浅谈Lua的面向对象特性
- 详解Lua中的变量相关知识点
- Lua脚本语言入门笔记
- Lua脚本调用外部脚本
- 详解Lua中的if语句的使用方法
- Lua中调用函数使用点号和冒号的区别
- Lua中的闭合函数、非全局函数与函数的尾调用详解
- Lua中强大的元方法__index详解
- Lua中调用C++函数示例
- Lua面向对象之类和继承浅析
- Lua性能优化技巧(一):前言
- Lua中获取table长度问题探讨