fr1kin

Using __gc to detect garbagecollection on non-userdata types

Nov 21st, 2014
413
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 2.12 KB | None | 0 0
  1. -- Keeping track of when any data is collected by lua's garbage collection
  2. -- Only works for Lua version 5.1 as newproxy was removed in Lua 5.2
  3.  
  4. -- How this works:
  5. -- Lua only calls the __gc metamethod for userdata values. This is because
  6. -- C should be handling the destruction of userdata as Lua doesn't know how.
  7. -- By using newproxy we can create our own userdata then append it to the
  8. -- values metatable using debug.setmetatable (which allows one to set the
  9. -- metatable of any type, not just tables). The idea is that when the object
  10. -- is deleted, the metatable will be deleted as well, thus calling the __gc
  11. -- metamethod.
  12.  
  13. -- In this example, I will show how one can do just this. Keep in mind if
  14. -- you want to give the value a metatable you must keep the __userData metamethod.
  15. -- Also note the __userData metamethod is NOT a real metamethod.
  16.  
  17. local table = {};
  18.  
  19. local function newUserdata(parent, key, value)
  20.     -- Create a new userdata
  21.     -- Takes a boolean argument to give it a metatable
  22.     -- initially, but I won't add that just to make the
  23.     -- example clearer.
  24.     local userdata = newproxy();
  25.     -- Set the metatable to an empty table.
  26.     debug.setmetatable(userdata, {});
  27.     -- Get the metatable that was just made.
  28.     local udmeta = debug.getmetatable(userdata);
  29.     -- Give it a __gc metatable which will be called
  30.     -- when it is destoryed
  31.     udmeta.__gc = function(ud)
  32.         print("trashed:", ud, parent, key, value);
  33.     end
  34.     return userdata;
  35. end
  36.  
  37. setmetatable(table,
  38.     {
  39.         -- When a new key is added to the table this will be called
  40.         __newindex = function(tab, key, value)
  41.             -- Set 'values' metatable and append a metamethod containing the userdata
  42.             debug.setmetatable(value, {__userData = newUserdata(tab, key, value)});
  43.             rawset(tab, key, value);
  44.         end,
  45.     }
  46. );
  47.  
  48. table["example_key"] = "example_value";
  49.  
  50. print("test:", table["example_key"]);
  51. -- prints: "test:   example_value"
  52.  
  53. print("collecting", collectgarbage("collect"));
  54. -- After running the file twice the GC will collect the
  55. -- previous table and print the following.
  56. -- "trashed:    userdata: 0000  table: 0000 example_key example_value
  57. -- "collecting  0"
Advertisement
Add Comment
Please, Sign In to add comment