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, const char *desc, struct lua_gc_node *parent)
{
const void *p = lua_topointer(L, -1);
if(p == NULL)
{
return;
}
if(isMark(p))
{
lua_pop(L, 1);
return;
}
struct lua_gc_node *currNode = gen_node(L, p, desc, parent);
bool weakk = false;
bool weakv = false;
if(lua_getmetatable(L, -1))
{
lua_pushliteral(L, "__mode");
lua_rawget(L, -2);
if (lua_isstring(L,-1))
{
const char *mode = lua_tostring(L, -1);
if (strchr(mode, 'k'))
{
weakk = true;
}
if (strchr(mode, 'v'))
{
weakv = true;
}
}
lua_pop(L,1);
luaL_checkstack(L, LUA_MINSTACK, NULL);
mark_table(L, ".[metatable]", currNode);
}
lua_pushnil(L);
while (lua_next(L, -2) != 0)
{
if(weakv)
{
lua_pop(L, 1);
}
else
{
char temp[128];
const char * _key = keystring(L, -2, temp);
mark_object(L, _key, currNode);
}
if(!weakk)
{
lua_pushvalue(L,-1);
mark_object(L, ".[key]", currNode);
}
}
lua_pop(L, 1);
}
const void *p = lua_topointer(L, -1);
取出栈顶的指针,下面用到指针做key存入一个哈希表里,来标记是否被遍历过
从metatable中取出__mode,来判断key,value是否为弱引用。如果是弱引用就不需要继续递归了,否则就继续调用mark_object递归
通过lua_next方法可以取出table中的key,value压入栈中
这里一定要严谨使用lua_pop(L, 1)管理虚拟栈的平衡,否则栈很快就溢出了
其他的函数可以多查找Lua手册,里面说的很详细,我就不一一列举啦。
另外在c语言中自己创建的内存,需要手动释放,否则也会有内存溢出问题
s = malloc(sizeof(struct lua_gc_node)); 通过malloc开辟内存
free(current_node); 对应使用free释放
递归完毕后,输出成Json格式的快照文件,方便Web端操作。
Web端功能
- 手机上文件传到PC上不太方便,所以弄了个web端直接接收上传的快照文件
- 取补集(可以取出2个快照之间,新创建了哪些东西没释放掉),比如战斗前快照,跟战斗后快照进行取补集,就可以知道战斗内有哪些是没释放的,立马就能查出泄露
- 取交集(可以查询常住内存)
上传文件的php代码
<?php
if ($_FILES["file"]["error"] > 0)
{
echo "错误:" . $_FILES["file"]["error"] . "<br>";
}
else
{
if (file_exists("upload/" . $_FILES["file"]["name"]))
{
echo $_FILES["file"]["name"] . " 文件已经存在。 ";
}
else
{
// 如果 upload 目录不存在该文件则将文件上传到 upload 目录下
move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"]);
echo "文件存储在: " . "upload/" . $_FILES["file"]["name"];
}
}
?>
如何把我们的代码编译到toluac中?
在网上搜这方面的资料,找到了之前同事(外号姐夫)写的博客,哈哈
https://www.jianshu.com/p/5a35602adef8
他讲的很清楚,我这里就不写了,可以看这篇文章把环境搭好。
另外还需要在tolua#中的LuaDLL.cs类里加上一个方法引入我们的库函数
然后在LuaManager.cs中把函数注册进去给lua使用
lua.OpenLibs (LuaDLL.luaopen_snapshot37);
lua.LuaSetField(-2, "snapshot37");
这样在lua代码里,我们就可以通过
local snapLib = require "snapshot37"
来引入我们的函数了
总结
- Lua内存分析工具的一些解决方案
- Lua中各种数据类型是怎么表示的
- 遍历GCObject的步骤
- 具体的一些LUA C API有不明白的可以多查看Lua官方文档
本文主要介绍了以上内容,欢迎找我一起交流讨论
参考
https://blog.codingnow.com/2012/12/lua_snapshot.html
http://www.cnblogs.com/yaukey/p/unity_lua_memory_leak_trace.html
https://www.jianshu.com/p/5a35602adef8
https://troydhanson.github.io/uthash
《Lua设计与实现》—— codedump (作者)
Lua内存分析工具的更多相关文章
- [原创]推荐一款强大的.NET程序内存分析工具.NET Memory Profiler
[原创]推荐一款强大的.NET程序内存分析工具.NET Memory Profiler 1 官方网站:http://memprofiler.com/2 下载地址:http://memprofiler. ...
- JS内存泄漏 和Chrome 内存分析工具简介(摘)
原文地址:http://web.jobbole.com/88463/ JavaScript 中 4 种常见的内存泄露陷阱 原文:Sebastián Peyrott 译文:伯乐在线专栏作者 - AR ...
- Android 内存分析工具 MAT(Memory Analyzer Tool)
如果使用DDMS确实发现了我们的程序中存在内存泄漏,那又如何定位到具体出现问题的代码片段,最终找到问题所在呢?如果从头到尾的分析代码逻辑,那肯定 会把人逼疯,特别是在维护别人写的代码的时候.这里介绍一 ...
- Android内存分析工具DDMS heap + MAT 安装和使用
一 Java内存分析工具扫盲 如果像我一样一点都不了解,可以先进行内存分析工具扫盲 MAT介绍: Eclipse Memory Analyzer(MAT)一个功能丰富的 JAVA 堆转储 ...
- Android内存优化(三)详解内存分析工具MAT
前言 在这个系列的前四篇文章中,我分别介绍了DVM.ART.内存泄漏和内存检测工具的相关知识点,这一篇我们通过一个小例子,来学习如何使用内存分析工具MAT. 1.概述 在进行内存分析时,我们可以使用M ...
- Eclipse MAT内存分析工具(Memory Analyzer Tool)
MAT内存分析工具 MAT是Memory Analyzer的简称,它是一款功能强大的Java堆内存分析器.可以用于查找内存泄露以及查看内存消耗情况.MAT是基于Eclipse开发的,是一款免费的性能分 ...
- [转] python运行时内存分析工具meliae
转自:https://my.oschina.net/markco/blog/601773 利用meliae来监控python进程的内存占用情况 meliae是一个python进程内存占用监控.分析工具 ...
- 内存分析工具-MAT(Memory Analyzer Tool)
内存分析工具-MAT(Memory Analyzer Tool) 首先查看如下代码,main函数中有一个成员变量map,map里被循环放入对象Hanson,hanson持有姓名和age还有friend ...
- android--------Eclipse中ddms heap内存分析工具
无 论怎么小心,想完全避免bad code是不可能的,此时就需要一些工具来帮助我们检查代码中是否存在会造成内存泄漏的地方. Android tools中的DDMS就带有一个很不错的内存监测工具Heap ...
随机推荐
- linux下yum命令出现Loaded plugins: fastestmirror
yum install的时候提示:Loaded plugins: fastestmirror fastestmirror是yum的一个加速插件,这里是插件提示信息是插件不能用了. 不能用就先别用呗,禁 ...
- dedecms====phpcms 区别==[工作]
{template "content","header"}{dede:include filename="head.htm"/} ----- ...
- CCNA -OSI七层模型
OSI (开放系统互联(Open System Interconnection)) OSI是Open System Interconnection的缩写,意为开放式系统互联.国际标准化组织(ISO)制 ...
- RPC架构简单理解
RPC(Remote Promote Call) 一种进程间通信方式.允许像调用本地服务一样调用远程服务. RPC框架的主要目标就是让远程服务调用更简单.透明.RPC框架负责屏蔽底层的传输方式(TCP ...
- Springmvc 并发访问的线程安全性问题
首先对于spring的IOC来说,对象是由Spring来帮我们管理,也就是在Spring启动的时候,在Spring容器中,由Spring给我们创建的,Spring会帮我们维护,一般都是单例的,也就是一 ...
- 史上最全的判断android,ios还是ipad访问,附上多种语言的实现方式
js判断: (function(a,b){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elain ...
- SpringMVC的filter怎么使用Autowired依赖注入bean
有的时候根据我们业务的需要,我们需要在web项目中定义一个自己的filter,并想在这个filter中使用@Autowired注入bean供我们使用.如果直接使用的话是不行的,需要我们在xml文件 ...
- python_如何通过实例方法名字调用方法?
案例: 某项目中,我们的代码使用的2个不同库中的图形类: Circle,Triangle 这两个类中都有一个获取面积的方法接口,但是接口的名字不一样 需求: 统一这些接口,不关心具体的接口,只要我调用 ...
- String 类的选择输出
package com.day_08.strings; /* * 通过API可知/String是在Java.lang包下的类,所以不用导包 */ public class StringDemo { p ...
- TP手册学习第四内置天
比较标签: eq:等于 heq:恒等于 gt:大于 lt:小于 (前面加上n则为否,如neq表示不等于)使用方法:{gt name="name" value= ...