C++與Lua交互內(nèi)存分配詳解
一、lua_State 創(chuàng)建
C/C++ 與 Lua 的交互是通過(guò) lua_State 這一句柄進(jìn)行交互。我們常規(guī)的創(chuàng)建都是通過(guò) luaL_newstate 這一輔助函數(shù),他的源碼實(shí)現(xiàn)如下:
LUALIB_API lua_State *luaL_newstate (void) {
lua_State *L = lua_newstate(l_alloc, NULL);
if (l_likely(L)) {
lua_atpanic(L, &panic);
lua_setwarnf(L, warnfoff, L); /* default is warnings off */
}
return L;
}
通過(guò)源碼可以知道,真正的創(chuàng)建是通過(guò) lua_newstate 函數(shù)
LUA_API lua_State *lua_newstate (lua_Alloc f, void *ud)
描述
函數(shù)創(chuàng)建并返回 lua_State 類(lèi)型的指針,后續(xù)通過(guò)這一指針和 Lua 進(jìn)行交互。這期間所有的內(nèi)存分配和釋放都會(huì)由參數(shù) f 函數(shù)進(jìn)行完成,包括該函數(shù)返回的 lua_State 。
參數(shù)
- 參數(shù) f :分配函數(shù)
- 參數(shù) ud :自定義用戶(hù)數(shù)據(jù),會(huì)攜帶進(jìn)入 f 函數(shù)
返回值:
lua_State 的指針
二、分配函數(shù)
Lua 中默認(rèn)的分配函數(shù)使用了 C 語(yǔ)言標(biāo)準(zhǔn)函數(shù)庫(kù)的標(biāo)準(zhǔn)函數(shù) malloc-realloc-free 進(jìn)行內(nèi)存的管理,以下便是 Lua 默認(rèn)分配函數(shù)。
static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
(void)ud; (void)osize; /* not used */
if (nsize == 0) {
free(ptr);
return NULL;
}
else
return realloc(ptr, nsize);
}
我們可以自行定義,只需遵循 lua_Alloc 格式,通過(guò) lua_newstate 函數(shù)或 lua_setallocf 函數(shù)設(shè)置即可生效
typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
參數(shù):
- 參數(shù) ud:
lua_newstate的第二個(gè)參數(shù)便會(huì)作為該參數(shù),并且是每次調(diào)用該分配函數(shù)都會(huì)攜帶。 - 參數(shù) ptr: 正要被分配、或是重新分配、或者是要被釋放的塊地址。
- 參數(shù) osize: 原始?jí)K的大小。
- 參數(shù) nsize: 需要申請(qǐng)的塊大小。
返回值:
- 如果需要?jiǎng)?chuàng)建新的內(nèi)存塊,則將創(chuàng)建的內(nèi)存塊指針?lè)祷亍?/li>
- 如果不需要?jiǎng)?chuàng)建內(nèi)存塊,則返回 NULL。
值得注意:
從分配函數(shù)的參數(shù)和返回值,已經(jīng)知道了這一函數(shù)的職責(zé):釋放原始?jí)K和創(chuàng)建新的塊并返回。所以會(huì)涉及以下一些小細(xì)節(jié):
- 當(dāng) ptr 是 NULL ,則原始內(nèi)存塊大小肯定是零,所以 Lua 使用 osize 存放某些調(diào)試信息。
- 當(dāng) ptr 是 NULL ,則分配函數(shù)必須分配并返回 nsize 指定大小的塊。如果無(wú)法分配相應(yīng)的塊,則返回 NULL 。如果此時(shí) nsize 為 零 則返回 NULL 。
- 當(dāng) nsize 為零時(shí),分配函數(shù)必須釋放 ptr 指向的塊并返回 NULL 。
- 如果 ptr 不是 NULL 并且 nsize 不為零,則可以使用
realloc進(jìn)行重新分配塊并返回(地址可能和原來(lái)一樣,也可能不一樣)。和第二點(diǎn)一樣,如果出錯(cuò)了則返回 NULL 。 - Lua 會(huì)假定分配函數(shù)在塊的新尺寸( nsize )小于或等于舊尺寸( osize )時(shí)不會(huì)失敗。
三、獲取當(dāng)前的內(nèi)存分配函數(shù)
通過(guò) lua_getallocf 獲取 Lua State 當(dāng)前的內(nèi)存分配函數(shù)
LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
參數(shù):
- 參數(shù) L: lua_State 指針。
- 參數(shù) ud: 會(huì)把當(dāng)前設(shè)置的自定義用戶(hù)數(shù)據(jù)設(shè)置給這一參數(shù)。
返回值:
Lua 當(dāng)前使用的內(nèi)存分配函數(shù)
四、設(shè)置內(nèi)存分配函數(shù)
通過(guò) lua_setallocf 設(shè)置新的內(nèi)存分配函數(shù)
LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
參數(shù):
- 參數(shù) L: lua_State 指針。
- 參數(shù) f: 需要設(shè)置新的內(nèi)存分配函數(shù)。
- 參數(shù) ud: 自定義用戶(hù)數(shù)據(jù)。
五、舉個(gè)例子
下面的代碼主要驗(yàn)證了三個(gè)步驟:
- 創(chuàng)建 lua_State 時(shí)傳入自己的內(nèi)存分配函數(shù)和自定義用戶(hù)數(shù)據(jù),函數(shù)中會(huì)打印所有的參數(shù)。
- 獲取當(dāng)前的分配函數(shù)。
- 替換當(dāng)前的分配函數(shù),最后關(guān)閉 lua_State 的時(shí)候會(huì)打印日志。
static void *alloc(void *ud, void *ptr, size_t osize, size_t nsize) {
const char *udContent = *(const char **) ud;
std::cout << "ud: " << udContent << "; *ptr: " << ptr << "; osize: " << osize << "; nsize: " << nsize << std::endl;
if (nsize == 0) {
free(ptr);
return nullptr;
} else
return realloc(ptr, nsize);
}
static void *newalloc(void *ud, void *ptr, size_t osize, size_t nsize) {
const char *udContent = *(const char **) ud;
std::cout << "新的分配函數(shù) " << "ud: " << udContent << "; *ptr: " << ptr << "; osize: " << osize << "; nsize: " << nsize << std::endl;
if (nsize == 0) {
free(ptr);
return nullptr;
} else
return realloc(ptr, nsize);
}
void allocationFunction() {
// 常規(guī)的創(chuàng)建 lua_State
// auto L = luaL_newstate();
printf("------------- 自定義內(nèi)存分配函數(shù) -------------\n");
// 自定義內(nèi)存分配數(shù)據(jù)
auto ud = "ud test message.";
auto L = lua_newstate(alloc, &ud);
printf("------------- 獲取 Lua 當(dāng)前的內(nèi)存分配函數(shù) -------------\n");
// lua_getallocf 第二個(gè)參數(shù)會(huì)返回之前設(shè)置的 自定義內(nèi)存分配數(shù)據(jù)
void *userData = nullptr;
lua_Alloc allocFunc = lua_getallocf(L, &userData);
const char *udContent = *(const char **) userData;
std::cout << &allocFunc << " " << udContent << std::endl;
printf("------------- 設(shè)置 Lua 的內(nèi)存分配函數(shù) -------------\n");
auto nud = "new ud test message.";
lua_setallocf(L, newalloc, &nud);
std::cout << "關(guān)閉 lua_State " << std::endl;
lua_close(L);
}
運(yùn)行之后的日志
------------- 自定義內(nèi)存分配函數(shù) -------------
ud: ud test message.; *ptr: 0x0; osize: 8; nsize: 1624
...... 省略很多內(nèi)存分配打印日志
ud: ud test message.; *ptr: 0x0; osize: 4; nsize: 30
------------- 獲取 Lua 當(dāng)前的內(nèi)存分配函數(shù) -------------
0x7ff7b7775f80 ud test message.
------------- 設(shè)置 Lua 的內(nèi)存分配函數(shù) -------------
關(guān)閉 lua_State
新的分配函數(shù) ud: new ud test message.; *ptr: 0x0; osize: 0; nsize: 0
...... 省略很多內(nèi)存分配打印日志
新的分配函數(shù) ud: new ud test message.; *ptr: 0x7fd3ef80c400; osize: 1624; nsize: 0
以上就是C++與Lua交互內(nèi)存分配詳解的詳細(xì)內(nèi)容,更多關(guān)于C++與Lua交互內(nèi)存分配的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C語(yǔ)言游戲必備:光標(biāo)定位與顏色設(shè)置的實(shí)現(xiàn)方法
本篇文章是對(duì)c語(yǔ)言中光標(biāo)定位與顏色設(shè)置的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
關(guān)于C語(yǔ)言和命令行之間的交互問(wèn)題
這篇文章主要介紹了C語(yǔ)言和命令行之間的交互,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-07-07
關(guān)于vector迭代器失效的幾種情況總結(jié)
下面小編就為大家?guī)?lái)一篇關(guān)于vector迭代器失效的幾種情況總結(jié)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-12-12
c++中priority_queue模擬的實(shí)現(xiàn)
priority_queue是C++標(biāo)準(zhǔn)庫(kù)中的一個(gè)容器適配器,用于實(shí)現(xiàn)優(yōu)先隊(duì)列的數(shù)據(jù)結(jié)構(gòu),本文主要介紹了c++中priority_queue模擬的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2024-09-09
C語(yǔ)言實(shí)現(xiàn)掃雷游戲(含注釋詳解)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)掃雷游戲,含注釋?zhuān)闹惺纠a介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06
一文掌握C++ const與constexpr及區(qū)別
C++ 11標(biāo)準(zhǔn)中,const 用于為修飾的變量添加“只讀”屬性而 constexpr關(guān)鍵字則用于指明其后是一個(gè)常量,編譯器在編譯程序時(shí)可以順帶將其結(jié)果計(jì)算出來(lái),而無(wú)需等到程序運(yùn)行階段,這樣的優(yōu)化極大地提高了程序的執(zhí)行效率,本文重點(diǎn)介紹C++ const與constexpr區(qū)別介紹,一起看看吧2024-02-02

