仔細看了崩潰的代碼以後,發現了一點蛛絲馬跡:
在luaopen_testlua函數裏的的調用如下:
lua_newtable----->lua_createtable---->luaH_new,在這個函數裏可以看到這些:
Table *luaH_new (lua_State *L, int narray, int nhash)
{
Table *t = luaM_new(L, Table);
luaC_link(L, obj2gco(t), LUA_TTABLE);
t->metatable = NULL;
t->flags = cast_byte(~0);
/* temporary values (kept only if some malloc fails) */
t->array = NULL;
t->sizearray = 0;
t->lsizenode = 0;
t->node = cast(Node *, dummynode); // 注意這裏
setarrayvector(L, t, narray);
setnodevector(L, t, nhash);
return t;
}
注意t->node = cast(Node *, dummynode);這一行。
這一行把t->node設置成lua內的一個空表dummynode,這個值是這樣定義的。
#define dummynode (&dummynode_)
static const Node dummynode_ = {
{{NULL}, LUA_TNIL}, /* value /
{{{NULL}, LUA_TNIL, NULL}} / key */
};
也就是說這個玩意其實是一個static變量,這也就是杯具的原因,因爲我的dll和exe裏各有一份lua源碼,所以在我的進程空間也就存在兩個dummynode。
這個dummynode是在dll離申請的。。。但是釋放的時候是在exe裏釋放的。所以下面這段代碼:
void luaH_free (lua_State *L, Table *t) {
if (t->node != dummynode)
{
luaM_freearray(L, t->node, sizenode(t), Node);
}
luaM_freearray(L, t->array, t->sizearray, TValue);
luaM_free(L, t);
}
上面的if判斷就成功了 (t->node指向dll裏的 dummynode,而這裏的dummynode是exe裏的)
所以這個函數就在傻乎乎的釋放dll裏的dummynode,然後vs的crt在釋放的時候又去檢查了這個指針,然後就崩潰了。。。
對於這種事情我覺得怎麼說呢?也許lua作者沒有考慮一個進程內有兩個lua模塊?也許他考慮了,但是沒法避免。這個也讓我理解了使用lib和使用dll的區別。這裏的解決辦法是把lua編譯成dll,然後所有模塊都引用這個dll。
一般情況下不會遇到這個崩潰,長時間運行時會觸發垃圾回收,因此上面的問題便顯現出來了,這個問題還真不好排查啊。
Lua的使用關係前後變化如圖:
解決方式:使用同一份lua源碼生成的lib來生成dll可以解決
參考:https://www.douban.com/note/98782461/
參考:https://www.it610.com/article/4783121.htm