最近给公司写了一个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复杂一些

  1. 因为要操作Lua栈,稍微写错一个栈没对称弹出,就会导致溢出,调试起来非常麻烦
  2. 因为c语言就像一块空地,什么都要自己造,连一些最基本的数据结构,都没有...
  3. 你需要编译成各个平台的库,这个后面会讲到如何跟tolua c编译到一起
工具分为2个部分
  1. c库生成快照
  2. web端接收上传快照,快照分析

Lua中哪些数据类型是需要GC的?

lua源码中定义了这些数据类型

  1. /*
  2. ** basic types
  3. */
  4. #define LUA_TNONE (-1)
  5. #define LUA_TNIL 0
  6. #define LUA_TBOOLEAN 1
  7. #define LUA_TLIGHTUSERDATA 2
  8. #define LUA_TNUMBER 3
  9. #define LUA_TSTRING 4
  10. #define LUA_TTABLE 5
  11. #define LUA_TFUNCTION 6
  12. #define LUA_TUSERDATA 7
  13. #define LUA_TTHREAD 8

使用GCObject的联合体将所有需要进行垃圾回收的数据囊括了进来。

  1. /*
  2. ** Union of all collectable objects
  3. */
  4. union GCObject {
  5. GCheader gch;
  6. union TString ts;
  7. union Udata u;
  8. union Closure cl;
  9. struct Table h;
  10. struct Proto p;
  11. struct UpVal uv;
  12. struct lua_State th; /* thread */
  13. };

但是还有一些不需要GC的数据类型,所以又定义了一个Value的联合体

  1. /*
  2. ** Union of all Lua values
  3. */
  4. typedef union {
  5. GCObject *gc;
  6. void *p;
  7. lua_Number n;
  8. int b;
  9. } Value;

这样就可以将Lua中所有的数据类型表示出来了,Lua还使用了一个宏来判断哪些数据类型是需要GC的

  1. #define iscollectable(o) (ttype(o) >= LUA_TSTRING)

通过这个我们可以知道,定义在LUA_TSTRING后的数据类型,都需要GC。一共有:LUA_TSTRING、LUA_TTABLE、LUA_TFUNCTION、LUA_TUSERDATA、LUA_TTHREAD

通过这样的遍历方式,从根节点开始递归整颗GC树

如何遍历table?

  1. void mark_object(lua_State *L, const char *desc, struct lua_gc_node *parent)
  2. {
  3. luaL_checkstack(L, LUA_MINSTACK, NULL);
  4. int t = lua_type(L, -1);
  5. switch (t) {
  6. case LUA_TTABLE:
  7. mark_table(L, desc, parent);
  8. break;
  9. case LUA_TUSERDATA:
  10. mark_userdata(L, desc, parent);
  11. break;
  12. case LUA_TFUNCTION:
  13. mark_function(L, desc, parent);
  14. break;
  15. case LUA_TTHREAD:
  16. mark_thread(L, desc, parent);
  17. break;
  18. default:
  19. lua_pop(L,1);
  20. break;
  21. }
  22. }
  23. void mark_table(lua_State *L, const char *desc, struct lua_gc_node *parent)
  24. {
  25. const void *p = lua_topointer(L, -1);
  26. if(p == NULL)
  27. {
  28. return;
  29. }
  30. if(isMark(p))
  31. {
  32. lua_pop(L, 1);
  33. return;
  34. }
  35. struct lua_gc_node *currNode = gen_node(L, p, desc, parent);
  36. bool weakk = false;
  37. bool weakv = false;
  38. if(lua_getmetatable(L, -1))
  39. {
  40. lua_pushliteral(L, "__mode");
  41. lua_rawget(L, -2);
  42. if (lua_isstring(L,-1))
  43. {
  44. const char *mode = lua_tostring(L, -1);
  45. if (strchr(mode, 'k'))
  46. {
  47. weakk = true;
  48. }
  49. if (strchr(mode, 'v'))
  50. {
  51. weakv = true;
  52. }
  53. }
  54. lua_pop(L,1);
  55. luaL_checkstack(L, LUA_MINSTACK, NULL);
  56. mark_table(L, ".[metatable]", currNode);
  57. }
  58. lua_pushnil(L);
  59. while (lua_next(L, -2) != 0)
  60. {
  61. if(weakv)
  62. {
  63. lua_pop(L, 1);
  64. }
  65. else
  66. {
  67. char temp[128];
  68. const char * _key = keystring(L, -2, temp);
  69. mark_object(L, _key, currNode);
  70. }
  71. if(!weakk)
  72. {
  73. lua_pushvalue(L,-1);
  74. mark_object(L, ".[key]", currNode);
  75. }
  76. }
  77. lua_pop(L, 1);
  78. }

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端功能

  1. 手机上文件传到PC上不太方便,所以弄了个web端直接接收上传的快照文件
  2. 取补集(可以取出2个快照之间,新创建了哪些东西没释放掉),比如战斗前快照,跟战斗后快照进行取补集,就可以知道战斗内有哪些是没释放的,立马就能查出泄露
  3. 取交集(可以查询常住内存)

上传文件的php代码

  1. <?php
  2. if ($_FILES["file"]["error"] > 0)
  3. {
  4. echo "错误:" . $_FILES["file"]["error"] . "<br>";
  5. }
  6. else
  7. {
  8. if (file_exists("upload/" . $_FILES["file"]["name"]))
  9. {
  10. echo $_FILES["file"]["name"] . " 文件已经存在。 ";
  11. }
  12. else
  13. {
  14. // 如果 upload 目录不存在该文件则将文件上传到 upload 目录下
  15. move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $_FILES["file"]["name"]);
  16. echo "文件存储在: " . "upload/" . $_FILES["file"]["name"];
  17. }
  18. }
  19. ?>

如何把我们的代码编译到toluac中?

在网上搜这方面的资料,找到了之前同事(外号姐夫)写的博客,哈哈

https://www.jianshu.com/p/5a35602adef8

他讲的很清楚,我这里就不写了,可以看这篇文章把环境搭好。

另外还需要在tolua#中的LuaDLL.cs类里加上一个方法引入我们的库函数

然后在LuaManager.cs中把函数注册进去给lua使用

  1. lua.OpenLibs (LuaDLL.luaopen_snapshot37);
  2. lua.LuaSetField(-2, "snapshot37");

这样在lua代码里,我们就可以通过

  1. local snapLib = require "snapshot37"

来引入我们的函数了

总结

  1. Lua内存分析工具的一些解决方案
  2. Lua中各种数据类型是怎么表示的
  3. 遍历GCObject的步骤
  4. 具体的一些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内存分析工具的更多相关文章

  1. [原创]推荐一款强大的.NET程序内存分析工具.NET Memory Profiler

    [原创]推荐一款强大的.NET程序内存分析工具.NET Memory Profiler 1 官方网站:http://memprofiler.com/2 下载地址:http://memprofiler. ...

  2. JS内存泄漏 和Chrome 内存分析工具简介(摘)

    原文地址:http://web.jobbole.com/88463/ JavaScript 中 4 种常见的内存泄露陷阱   原文:Sebastián Peyrott 译文:伯乐在线专栏作者 - AR ...

  3. Android 内存分析工具 MAT(Memory Analyzer Tool)

    如果使用DDMS确实发现了我们的程序中存在内存泄漏,那又如何定位到具体出现问题的代码片段,最终找到问题所在呢?如果从头到尾的分析代码逻辑,那肯定 会把人逼疯,特别是在维护别人写的代码的时候.这里介绍一 ...

  4. Android内存分析工具DDMS heap + MAT 安装和使用

    一  Java内存分析工具扫盲 如果像我一样一点都不了解,可以先进行内存分析工具扫盲   MAT介绍:     Eclipse Memory Analyzer(MAT)一个功能丰富的 JAVA 堆转储 ...

  5. Android内存优化(三)详解内存分析工具MAT

    前言 在这个系列的前四篇文章中,我分别介绍了DVM.ART.内存泄漏和内存检测工具的相关知识点,这一篇我们通过一个小例子,来学习如何使用内存分析工具MAT. 1.概述 在进行内存分析时,我们可以使用M ...

  6. Eclipse MAT内存分析工具(Memory Analyzer Tool)

    MAT内存分析工具 MAT是Memory Analyzer的简称,它是一款功能强大的Java堆内存分析器.可以用于查找内存泄露以及查看内存消耗情况.MAT是基于Eclipse开发的,是一款免费的性能分 ...

  7. [转] python运行时内存分析工具meliae

    转自:https://my.oschina.net/markco/blog/601773 利用meliae来监控python进程的内存占用情况 meliae是一个python进程内存占用监控.分析工具 ...

  8. 内存分析工具-MAT(Memory Analyzer Tool)

    内存分析工具-MAT(Memory Analyzer Tool) 首先查看如下代码,main函数中有一个成员变量map,map里被循环放入对象Hanson,hanson持有姓名和age还有friend ...

  9. android--------Eclipse中ddms heap内存分析工具

    无 论怎么小心,想完全避免bad code是不可能的,此时就需要一些工具来帮助我们检查代码中是否存在会造成内存泄漏的地方. Android tools中的DDMS就带有一个很不错的内存监测工具Heap ...

随机推荐

  1. dede后台出现   保存目录数据时失败,请检查你的输入资料是否存在问题

    dede 5.7无法增加顶级/二级栏目,保存目录数据时失败,请检查你的输入资料是否存在问题!执行了SQL还是不行 解决档案:用正常可以添加栏目的,将E:\wamp\www\dededln\back(d ...

  2. HTML 5 <embed> 标签

    定义和用法 <embed> 标签定义嵌入的内容,比如插件. 实例 <embed src="helloworld.swf" />

  3. 用photoshop将图片四角变成圆角

    1.用PS打开一张图片,用矩形选框工具,选出你要保留的的那一部分,"选择→修改→平滑".在弹出的选框里添入数值,值越大角就越圆. 2.然后选择"选择→反选"再按 ...

  4. mysql修改表和列

    mysql修改列 mysql增加列,修改列名.列属性,删除列语句   mysql修改表名,列名,列类型,添加表列,删除表列     alter table test rename test1; --修 ...

  5. 【笔记】css浮动的一些个人见解

    看<css 权威指南>已经有差不多两个月时间了,正好最近读到浮动这一章写一写个人对立面的概念的一些见解吧. 说之前还真不得不说这本书卖之前以为会说得通俗易懂读后才发现其实有些概念从文意上理 ...

  6. 全新的软件项目,好的开始决定了成功一半!(需求&计划)

    刚看完“无问西东”,电影里说人总归还是要留下些足迹(文字)的,那么赶紧跑图书馆来留下些文字. 最近去瑞士启动了一个新的项目,那么早上做项目,晚上总结留下了一张张思维导图来记录当时的感受, 手稿如下,字 ...

  7. shopnc IM配置过程

    im配置windows下,修改chat下和data下的config,安装node,覆盖node下文件即可

  8. Activiti简介

    Activiti项目是一项新的基于Apache许可的开源BPM平台,从基础开始构建,旨在提供支持新的BPMN 2.0标准,包括支持对象管理组(OMG),面对新技术的机遇,诸如互操作性和云架构,提供技术 ...

  9. java里程碑之泛型--泛型基本语法

    1,java7提供的泛型菱形语法 在java7之前,如果使用带泛型的接口和类定义变量初始化对象的时候,构造器后面也必须带上泛型,这有点恶心的.以前我在公司一直使用的java6,所以我也已经习惯了这种写 ...

  10. CSS--开篇

    1,什么是CSS? 层叠样式表(Cascading Style Sheet ),定义了如何显示HTML元素,用来控制网页的样式和布局. 引入CSS后:HTML标记专门用于定义网页的内容,而使用CSS来 ...