Lua内存分析工具
最近给公司写了一个lua内存分析工具,可以方便的分析出Lua内存泄露问题(虽然还没正式使用,但我是这样想的,哈哈哈),有图形化界面操作,方便手机端上传快照等功能
内存分析我是在c语言端写的,也有人写过lua端的分析工具,也蛮好用的,不过lua分析工具本身也会影响到lua的内存占用(尽管用的是弱表缓存的),也会有些不准确。
Lua方案:https://github.com/yaukeywang/LuaMemorySnapshotDump
然后找到了云风大神写的C语言解决方案
https://blog.codingnow.com/2012/12/lua_snapshot.html
这个库功能颇为简单,简单到连对象引用链都没有,只打印出key名和内存地址
所以我还是决定自己造轮子改进一下云风大神的方案,也是更进一步的去学习一下lua的c api
C实现起来比Lua复杂一些
- 因为要操作Lua栈,稍微写错一个栈没对称弹出,就会导致溢出,调试起来非常麻烦
- 因为c语言就像一块空地,什么都要自己造,连一些最基本的数据结构,都没有...
- 你需要编译成各个平台的库,这个后面会讲到如何跟tolua c编译到一起
工具分为2个部分
- c库生成快照
- web端接收上传快照,快照分析
Lua中哪些数据类型是需要GC的?
lua源码中定义了这些数据类型
/* ** basic types */ #define LUA_TNONE (-1) #define LUA_TNIL 0 #define LUA_TBOOLEAN 1 #define LUA_TLIGHTUSERDATA 2 #define LUA_TNUMBER 3 #define LUA_TSTRING 4 #define LUA_TTABLE 5 #define LUA_TFUNCTION 6 #define LUA_TUSERDATA 7 #define LUA_TTHREAD 8
使用GCObject的联合体将所有需要进行垃圾回收的数据囊括了进来。
/* ** Union of all collectable objects */ union GCObject { GCheader gch; union TString ts; union Udata u; union Closure cl; struct Table h; struct Proto p; struct UpVal uv; struct lua_State th; /* thread */ };
但是还有一些不需要GC的数据类型,所以又定义了一个Value的联合体
/* ** Union of all Lua values */ typedef union { GCObject *gc; void *p; lua_Number n; int b; } Value;
这样就可以将Lua中所有的数据类型表示出来了,Lua还使用了一个宏来判断哪些数据类型是需要GC的
#define iscollectable(o) (ttype(o) >= LUA_TSTRING)
通过这个我们可以知道,定义在LUA_TSTRING后的数据类型,都需要GC。一共有:LUA_TSTRING、LUA_TTABLE、LUA_TFUNCTION、LUA_TUSERDATA、LUA_TTHREAD
通过这样的遍历方式,从根节点开始递归整颗GC树
如何遍历table?
void mark_object(lua_State *L, const char *desc, struct lua_gc_node *parent) { luaL_checkstack(L, LUA_MINSTACK, NULL); int t = lua_type(L, -1); switch (t) { case LUA_TTABLE: mark_table(L, desc, parent); break; case LUA_TUSERDATA: mark_userdata(L, desc, parent); break; case LUA_TFUNCTION: mark_function(L, desc, parent); break; case LUA_TTHREAD: mark_thread(L, desc, parent); break; default: lua_pop(L,1); break; } } void mark_table(lua_State *L, co