zoukankan      html  css  js  c++  java
  • lua垃圾回收之空表

    故事背景:

      自己手动手写的一个lua外部库luaopen_xxx,采用了tolua++1.0.93,编译后得到xxx.dll,当在luajit中require 'xxx'后是正常的,但如果运行环境换成lua5.1.4,进程崩溃,调试后发现,出问题的现场在这个函数:

    /*
    ** generic allocation routine.
    */
    void *luaM_realloc_ (lua_State *L, void *block, size_t osize, size_t nsize) {
      global_State *g = G(L);
      lua_assert((osize == 0) == (block == NULL));
      block = (*g->frealloc)(g->ud, block, osize, nsize);//就挂在这行了,内存问题
      if (block == NULL && nsize > 0)
        luaD_throw(L, LUA_ERRMEM);
      lua_assert((nsize == 0) == (block == NULL));
      g->totalbytes = (g->totalbytes - osize) + nsize;
      return block;
    }

    堆栈如下:

    如果解决这个问题:

      先思考一下,free的时候崩溃,那就是内存问题,常见的有这么几种情况

    • 内存重复释放
    • 释放空指针
    • 释放非堆区内存
    • 虽然是堆区的内存,但由于bug导致偏移计算错误
    • 指针未初始化导致不该释放的野指针释放问题

    接下来采用排除法,尝试注释掉所有的自己的代码,启动直接执行tolua环境初始化的函数,tolua_open(tolua_S);

    进程直接崩溃,进一步二分排队法,发现执行到这几行代码会出问题

    果然跟tolua++有关 ,那我们尝试不使用tolua++,单独执行这几行代码吧,照样崩溃。

    这是一个空表,记得哪里看到过,luaC扩展库经常出现版本问题是因为,lua的所有空表其实都是指向同一个全局实例,由于版本不一样,导致这个全局变量的内存地址不一样

    那应该就是空表地址不一致造成的了,那我们加一下打印吧,在lua.exe 和xxx.dll各自去打印一下空表地址即可

    在ltable.c:73行增加打返回空表地址

    #define dummynode        (&dummynode_)
    
    static /*const*/ Node dummynode_ = {
      {{NULL}, LUA_TNIL},  /* value */
      {{{NULL}, LUA_TNIL, NULL}}  /* key */
    };
    
    void *Get_dummynode() { return dummynode; }

    在lua.c及xxx.c(动态库位置增加打钱)

    extern void *Get_dummynode();
    
    printf("%p
    ", Get_dummynode());

    执行结果,果然内存址不一样,所以会执行下面这段代码:

    好了,问题水落石出了,怎么避免这个问题呢?

    • 避免使用空表吧,
    • 或者知道问题就好使用luajit就不会有这个问题了
    • 当然还可以避免使用tolua++

    吐槽一下lua实现对这个全局变量的依赖及C的全局变量内存空间的不一致。当然想想,lua最初的设计是作为嵌入式语言,如果直接把整块编译进同一个模块也不会有这个问题

  • 相关阅读:
    关于codeblocks插件(持续更新)
    自定义gvim配色方案qiucz.vim的源码
    mark it
    poj 1032
    poj 1028
    最小公倍数是lcm
    problems
    hdu 1067
    某些题的做法。。。
    突然明白了什么
  • 原文地址:https://www.cnblogs.com/linbc/p/5549573.html
Copyright © 2011-2022 走看看