lua性能优化之memory monitor

6 篇文章 0 订阅

lua性能优化之memory monitor

https://blog.csdn.net/zjz520yy/article/details/79777392

 

准备工作:
1.在编写mm库前必须对lua c api要熟悉,否则会无从下手,这是一个痛苦的过程,还好风云大大对这个api进行的翻译,相对来说写lua c 库就轻松很多了,api翻译地址为:https://www.codingnow.com/2000/download/lua_manual.html#lua_getstack。
2.在扩展snapshot库时会用到uthash这个第三方工具,主要是使用哈希表的方式来做快照存储以及数组来存储对象引用路径的,地址为:https://troydhanson.github.io/uthash/userguide.html

mm库具有的功能:
1.快照Registry或者_G表。
2.计算Lua对象内存大小以及引用关系。
3.储存快照。

快照Registry或者_G表:lua里面的回收对象类型如下图所示:
这里写图片描述
所以我们只需提供MarkObject,MarkTable,MarkUserData,MarkFunction,MarkThread来递归统计对象即可。核心代码如下所示:

void MarkObject(lua_State *L, const char *desc, const char *parent)
{
    luaL_checkstack(L, LUA_MINSTACK, NULL);

    int type = lua_type(L, -1);
    switch (type) {
    case LUA_TTABLE:
        MarkTable(L, desc, parent);
        break;
    case LUA_TUSERDATA:
        MarkUserData(L, desc, parent);
        break;
    case LUA_TFUNCTION:
        MarkFunction(L, desc, parent);
        break;
    case LUA_TTHREAD:
        MarkThread(L, desc, parent);
        break;
    default:
        lua_pop(L,1);
        break;
    }
}

void MarkTable(lua_State *L, const char *desc, const char *parent)
{
    const void *addr = lua_topointer(L, -1);
    if (addr == NULL)
    {
        return;
    }

    struct GCObject *obj = GetGCObject(addr);
    if (obj != NULL)
    {
        AddRefPath(obj, desc, parent);

        lua_pop(L, 1);
    }
    else
    {
        obj = AddGCObject(L, addr, 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);

            char **path = (char**)utarray_front(obj->paths);
            MarkTable(L, "[metatable]", *path);
        }

        lua_pushnil(L);
        while (lua_next(L, -2) != 0)
        {
            if (weakv)
            {
                lua_pop(L, 1);
            }
            else
            {
                char temp[128];
                const char *name = KeyString(L, -2, temp);

                char **path = (char**)utarray_front(obj->paths);
                MarkObject(L, name, *path);
            }

            if (!weakk)
            {
                lua_pushvalue(L, -1);

                char **path = (char**)utarray_front(obj->paths);
                MarkObject(L, "[key]", *path);
            }
        }

        lua_pop(L, 1);
    }
}

void MarkUserData(lua_State *L, const char *desc, const char *parent)
{
    const void *addr = lua_topointer(L, -1);
    if (addr == NULL)
    {
        return;
    }

    struct GCObject *obj = GetGCObject(addr);
    if(obj != NULL)
    {
        AddRefPath(obj, desc, parent);

        lua_pop(L, 1);
    }
    else
    {
        obj = AddGCObject(L, addr, desc, parent);

        if (lua_getmetatable(L, -1))
        {
            char **path = (char**)utarray_front(obj->paths);
            MarkTable(L, "[metatable]", *path);
        }

        GetUserValue(L, -1);
        if (lua_isnil(L, -1))
        {
            lua_pop(L, 2);
        }
        else
        {
            char **path = (char**)utarray_front(obj->paths);
            MarkTable(L, "[uservalue]", *path);

            lua_pop(L,1);
        }
    }
}

void MarkFunction(lua_State *L, const char *desc, const char *parent)
{
    const void *addr = lua_topointer(L, -1);
    if (addr == NULL)
    {
        return;
    }

    struct GCObject *obj = GetGCObject(addr);
    if(obj != NULL)
    {
        AddRefPath(obj, desc, parent);

        lua_pop(L, 1);
    }
    else
    {
        obj = AddGCObject(L, addr, desc, parent);

        char **path = (char**)utarray_front(obj->paths);
        MarkFunctionEnv(L, *path);

        int i;
        for (i=1;;i++)
        {
            const char *name = lua_getupvalue(L, -1, i);
            if (name == NULL)
            {
                break;
            }

            path = (char**)utarray_front(obj->paths);
            MarkObject(L, name[0] ? name : "[upvalue]", *path);
        }

        if (lua_iscfunction(L, -1) == 0)
        {
            lua_Debug ar;
            lua_getinfo(L, ">S", &ar);

            char temp[128];
            sprintf(temp, "[%s:%d]", ar.short_src, ar.linedefined);

            path = (char**)utarray_front(obj->paths);
            AppendRefPath(obj, path, temp);
        }
        else
        {
            lua_pop(L, 1);
        }
    }
}

void MarkThread(lua_State *L, const char *desc, const char *parent)
{
    const void *addr = lua_topointer(L, -1);
    if (addr == NULL)
    {
        return;
    }

    struct GCObject *obj = GetGCObject(addr);
    if (obj != NULL)
    {
        AddRefPath(obj, desc, parent);

        lua_pop(L, 1);
    }
    else
    {
        obj = AddGCObject(L, addr, desc, parent);

        int level = 0;
        lua_State *cL = lua_tothread(L, -1);
        if (cL == L)
        {
            level = 1;
        }
        else
        {
            // mark stack
            int top = lua_gettop(cL);
            luaL_checkstack(cL, 1, NULL);
            int i;
            char temp[16];
            for (i = 0; i < top; i++)
            {
                lua_pushvalue(cL, i + 1);
                sprintf(temp, "[thread %d]", i + 1);
                MarkObject(cL, temp, parent);
            }
        }

        lua_Debug ar;
        while (lua_getstack(cL, level, &ar))
        {
            lua_getinfo(cL, "Sl", &ar);

            char temp[128];
            if (ar.currentline >= 0)
            {
                sprintf(temp, "[%s:%d]", ar.short_src, ar.currentline);
            }
            else
            {
                sprintf(temp, "[%s]", ar.short_src);
            }

            char **path = (char**)utarray_front(obj->paths);
            AppendRefPath(obj, path, temp);

            int i,j;
            for (j = 1; j > -1; j-=2)
            {
                for (i = j;;i+=j)
                {
                    const char *name = lua_getlocal(cL, &ar, i);
                    if (name == NULL)
                    {
                        break;
                    }

                    snprintf(temp, sizeof(temp), "%s : %s:%d", name, ar.short_src, ar.currentline);

                    path = (char**)utarray_front(obj->paths);
                    MarkObject(cL, temp, *path);
                }
            }

            ++level;
        }

        lua_pop(L,1);
    }
}

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274

计算Lua对象内存大小以及引用关系:由于lua并没有提供对象内存的计算方式,只能对整体内存进行统计,所以这里就做引用关系的处理。内存对象计算往后想到好的办法再补上。核心代码如下:

void AddRefPath(struct GCObject *obj, const char *desc, const char *parent)
{
    UT_string *temp;
    utstring_new(temp);

    if (parent != NULL)
    {
        utstring_printf(temp, "%s.%s", parent, desc);
    }
    else
    {
        utstring_printf(temp, "%s", desc);
    }

    char *path = utstring_body(temp);
    utarray_push_back(obj->paths, &path);

    utstring_free(temp);
}

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

储存快照:快照存储在hash表中,并通过json串形式写入到本地文件中。核心代码如下:

void GenJsonResult(lua_State *L, const char *fileName)
{
    FILE *fp = fopen(fileName, "w+");
    if (fp == NULL)
    {
        printf("无法打开文件\n");
        FreeGCHash();
        return;
    }

    int count = lua_gc(L, LUA_GCCOUNT, 0);

    UT_string *jsonStr;
    utstring_new(jsonStr);
    utstring_printf(jsonStr, "{count:%d, items:[", count);

    unsigned int hashLen = HASH_COUNT(gcHash);
    unsigned int hashIndex = 0;

    // 遍历统计对象列表,填充json字符串串
    struct GCObject *obj;
    for (obj = gcHash; obj != NULL; obj = obj->hh.next)
    {
        utstring_printf(jsonStr, "{addr:\"%p\", type:\"%s\", memory:%d, refPath:\"",
                        obj->addr,  
                        obj->type,
                        obj->memory);

        unsigned int arrayLen = utarray_len(obj->paths);
        unsigned int arrayIndex = 0;

        char **path = NULL;
        while ((path = (char**)utarray_next(obj->paths, path))) {
            utstring_printf(jsonStr, "%s", *path);

            if (arrayIndex != (arrayLen - 1))
            {
                utstring_printf(jsonStr, ",");
            }
            arrayIndex++;
        }
        utstring_printf(jsonStr, "\"}");

        if (hashIndex != (hashLen - 1))
        {
            utstring_printf(jsonStr, ",\n");
        }
        hashIndex++;
    }

    utstring_printf(jsonStr, "]}");

    fputs(utstring_body(jsonStr), fp);

    fclose(fp);

    utstring_free(jsonStr);

    FreeGCHash();
}

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60

mm库的测试结果:经验证mm运行正确。
测试用例如下:
这里写图片描述
测试输出如下:

————————————————
版权声明:本文为CSDN博主「金朝」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/zjz520yy/article/details/79777392

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值