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 ...
随机推荐
- 机器学习——kNN(1)基本原理
=================================版权声明================================= 版权声明:原创文章 禁止转载 请通过右侧公告中的“联系邮 ...
- asp.net -mvc框架复习(4)-ASP.NET MVC中的约定规则
1.路由规则 using System;using System.Collections.Generic;using System.Linq;using System.Web;using System ...
- Source Insight、Xshell(putty)、Xftp
body, table{font-family: 微软雅黑} table{border-collapse: collapse; border: solid gray; border-width: 2p ...
- 开始学习 Backbone
[转]开始学习 Backbone 如何将模型-视图-控制器 (MVC) 架构引入 Ajax Web 应用程序 如何高效管理 Web 应用程序中的数目众多的 JavaScript 代码行是一个挑战.As ...
- list类型
list是一个链表结构,可以模拟栈,队列 lpush list中压入一个元素 模拟栈 lrange 取出list的中的元素(0 -1 表示从头取到尾) rpush list中压入一个元素 模 ...
- lambda高级进阶--延迟执行
前面的整理我们也已经说到了,使用lambda表达式的主要原因是,将代码的执行延迟到一个合适的时间点.在使用lambda表达式的时候务必记住一点就是说lambda表达式都是延迟执行的. 延迟执行代码的原 ...
- 在VMware中安装ubuntu
如果想在自己设置它的属性,比如时区,语言支持之类的,在开机时按[enter], 否则就是默认的设置了,英文语言,而且还不好调.
- python中的time模块
time模块--时间获取和转换 time模块提供各种时间相关的功能 与时间相关的模块有:time,datetime,calendar 必要说明: 这个模块的功能不是适用于所有的平台 这个模块中定义的大 ...
- .NET Core 2.0 问题杂记
一. Ubuntu 14.04 安装 1.安装之前请先删除之前的.net core 版本 命令如下: 1.1 获取安装的.net core 版本 sudo apt --installed list | ...
- WebService 的工作原理
Web Service基本概念 Web Service也叫XML Web Service WebService是一种可以接收从Internet或者Intranet上的其它系统中传递过来的请求,轻量级的 ...