Lua: garbage collection + userdata

2019-04-29 23:04发布

问题:

Supposing the following situation:

typedef struct rgb_t {float r,g,b} rbg_t;

// a function for allocating the rgb struct
rgb_t* rgb(r,g,b) {
 rgb_t* c = malloc(sizeof(rgb_t));
 c->r=r;
 c->g=g;
 c->b=b;
 return c;
}

// expose rgb creation to lua
int L_rgb (lua_State* L) {
 rgb_t** ud = (rgb_t **) lua_newuserdata(L, sizeof(rgb_t *));
 *ud = rgb(lua_tonumber(L,1),lua_tonumber(L,2),lua_tonumber(L,3));
 return 1;
}

When the L_rgb function is called from Lua two allocations happen. Lua allocates new userdata and the rgb constructor function allocates for the struct. What happens to the userdata variable when the variable goes out of scope in Lua? If it is garbage collected what happens to the allocation of the struct?

回答1:

You have two approaches to this situation, and both could apply to your specific case. Other cases drive you more strongly to choose one over the other.

  1. You can do as you do in your sample, and use malloc() to get your private data block, and store a pointer to it in a full userdata. If you do this, then you must set a metatable on the userdata, and use its __gc metamethod to free the allocated block when the userdata gets garbage collected.

  2. You can use the userdata itself as the allocation for your private data block, by calling lua_newuserdata() in place of malloc(). In this case you do not need to have an __gc metamethod because Lua will be directly managing the lifetime of the allocation. You might still want to have a metatable so that you can use its __index entry to create the appearance of members named r, g, and b that retrieve their values from your struct.

Either way, you need to think about error handling.



回答2:

add a metatable to your userdata, and set the __gc key to your deallocation function. See the docs