github.com/awirix/lua@v1.6.0/_lua5.1-tests/gc.lua (about) 1 print('testing garbage collection') 2 3 collectgarbage() 4 5 _G["while"] = 234 6 7 limit = 5000 8 9 10 11 contCreate = 0 12 13 print('tables') 14 while contCreate <= limit do 15 local a = {}; a = nil 16 contCreate = contCreate+1 17 end 18 19 a = "a" 20 21 contCreate = 0 22 print('strings') 23 while contCreate <= limit do 24 a = contCreate .. "b"; 25 a = string.gsub(a, '(%d%d*)', string.upper) 26 a = "a" 27 contCreate = contCreate+1 28 end 29 30 31 contCreate = 0 32 33 a = {} 34 35 print('functions') 36 function a:test () 37 while contCreate <= limit do 38 loadstring(string.format("function temp(a) return 'a%d' end", contCreate))() 39 assert(temp() == string.format('a%d', contCreate)) 40 contCreate = contCreate+1 41 end 42 end 43 44 a:test() 45 46 -- collection of functions without locals, globals, etc. 47 do local f = function () end end 48 49 50 print("functions with errors") 51 prog = [[ 52 do 53 a = 10; 54 function foo(x,y) 55 a = sin(a+0.456-0.23e-12); 56 return function (z) return sin(%x+z) end 57 end 58 local x = function (w) a=a+w; end 59 end 60 ]] 61 do 62 local step = 1 63 if rawget(_G, "_soft") then step = 13 end 64 for i=1, string.len(prog), step do 65 for j=i, string.len(prog), step do 66 pcall(loadstring(string.sub(prog, i, j))) 67 end 68 end 69 end 70 71 print('long strings') 72 x = "01234567890123456789012345678901234567890123456789012345678901234567890123456789" 73 assert(string.len(x)==80) 74 s = '' 75 n = 0 76 k = 300 77 while n < k do s = s..x; n=n+1; j=tostring(n) end 78 assert(string.len(s) == k*80) 79 s = string.sub(s, 1, 20000) 80 s, i = string.gsub(s, '(%d%d%d%d)', math.sin) 81 assert(i==20000/4) 82 s = nil 83 x = nil 84 85 assert(_G["while"] == 234) 86 87 88 local bytes = gcinfo() 89 while 1 do 90 local nbytes = gcinfo() 91 if nbytes < bytes then break end -- run until gc 92 bytes = nbytes 93 a = {} 94 end 95 96 97 local function dosteps (siz) 98 collectgarbage() 99 collectgarbage"stop" 100 local a = {} 101 for i=1,100 do a[i] = {{}}; local b = {} end 102 local x = gcinfo() 103 local i = 0 104 repeat 105 i = i+1 106 until collectgarbage("step", siz) 107 assert(gcinfo() < x) 108 return i 109 end 110 111 assert(dosteps(0) > 10) 112 assert(dosteps(6) < dosteps(2)) 113 assert(dosteps(10000) == 1) 114 assert(collectgarbage("step", 1000000) == true) 115 assert(collectgarbage("step", 1000000)) 116 117 118 do 119 local x = gcinfo() 120 collectgarbage() 121 collectgarbage"stop" 122 repeat 123 local a = {} 124 until gcinfo() > 1000 125 collectgarbage"restart" 126 repeat 127 local a = {} 128 until gcinfo() < 1000 129 end 130 131 lim = 15 132 a = {} 133 -- fill a with `collectable' indices 134 for i=1,lim do a[{}] = i end 135 b = {} 136 for k,v in pairs(a) do b[k]=v end 137 -- remove all indices and collect them 138 for n in pairs(b) do 139 a[n] = nil 140 assert(type(n) == 'table' and next(n) == nil) 141 collectgarbage() 142 end 143 b = nil 144 collectgarbage() 145 for n in pairs(a) do error'cannot be here' end 146 for i=1,lim do a[i] = i end 147 for i=1,lim do assert(a[i] == i) end 148 149 150 print('weak tables') 151 a = {}; setmetatable(a, {__mode = 'k'}); 152 -- fill a with some `collectable' indices 153 for i=1,lim do a[{}] = i end 154 -- and some non-collectable ones 155 for i=1,lim do local t={}; a[t]=t end 156 for i=1,lim do a[i] = i end 157 for i=1,lim do local s=string.rep('@', i); a[s] = s..'#' end 158 collectgarbage() 159 local i = 0 160 for k,v in pairs(a) do assert(k==v or k..'#'==v); i=i+1 end 161 assert(i == 3*lim) 162 163 a = {}; setmetatable(a, {__mode = 'v'}); 164 a[1] = string.rep('b', 21) 165 collectgarbage() 166 assert(a[1]) -- strings are *values* 167 a[1] = nil 168 -- fill a with some `collectable' values (in both parts of the table) 169 for i=1,lim do a[i] = {} end 170 for i=1,lim do a[i..'x'] = {} end 171 -- and some non-collectable ones 172 for i=1,lim do local t={}; a[t]=t end 173 for i=1,lim do a[i+lim]=i..'x' end 174 collectgarbage() 175 local i = 0 176 for k,v in pairs(a) do assert(k==v or k-lim..'x' == v); i=i+1 end 177 assert(i == 2*lim) 178 179 a = {}; setmetatable(a, {__mode = 'vk'}); 180 local x, y, z = {}, {}, {} 181 -- keep only some items 182 a[1], a[2], a[3] = x, y, z 183 a[string.rep('$', 11)] = string.rep('$', 11) 184 -- fill a with some `collectable' values 185 for i=4,lim do a[i] = {} end 186 for i=1,lim do a[{}] = i end 187 for i=1,lim do local t={}; a[t]=t end 188 collectgarbage() 189 assert(next(a) ~= nil) 190 local i = 0 191 for k,v in pairs(a) do 192 assert((k == 1 and v == x) or 193 (k == 2 and v == y) or 194 (k == 3 and v == z) or k==v); 195 i = i+1 196 end 197 assert(i == 4) 198 x,y,z=nil 199 collectgarbage() 200 assert(next(a) == string.rep('$', 11)) 201 202 203 -- testing userdata 204 collectgarbage("stop") -- stop collection 205 local u = newproxy(true) 206 local s = 0 207 local a = {[u] = 0}; setmetatable(a, {__mode = 'vk'}) 208 for i=1,10 do a[newproxy(u)] = i end 209 for k in pairs(a) do assert(getmetatable(k) == getmetatable(u)) end 210 local a1 = {}; for k,v in pairs(a) do a1[k] = v end 211 for k,v in pairs(a1) do a[v] = k end 212 for i =1,10 do assert(a[i]) end 213 getmetatable(u).a = a1 214 getmetatable(u).u = u 215 do 216 local u = u 217 getmetatable(u).__gc = function (o) 218 assert(a[o] == 10-s) 219 assert(a[10-s] == nil) -- udata already removed from weak table 220 assert(getmetatable(o) == getmetatable(u)) 221 assert(getmetatable(o).a[o] == 10-s) 222 s=s+1 223 end 224 end 225 a1, u = nil 226 assert(next(a) ~= nil) 227 collectgarbage() 228 assert(s==11) 229 collectgarbage() 230 assert(next(a) == nil) -- finalized keys are removed in two cycles 231 232 233 -- __gc x weak tables 234 local u = newproxy(true) 235 setmetatable(getmetatable(u), {__mode = "v"}) 236 getmetatable(u).__gc = function (o) os.exit(1) end -- cannot happen 237 collectgarbage() 238 239 local u = newproxy(true) 240 local m = getmetatable(u) 241 m.x = {[{0}] = 1; [0] = {1}}; setmetatable(m.x, {__mode = "kv"}); 242 m.__gc = function (o) 243 assert(next(getmetatable(o).x) == nil) 244 m = 10 245 end 246 u, m = nil 247 collectgarbage() 248 assert(m==10) 249 250 251 -- errors during collection 252 u = newproxy(true) 253 getmetatable(u).__gc = function () error "!!!" end 254 u = nil 255 assert(not pcall(collectgarbage)) 256 257 258 if not rawget(_G, "_soft") then 259 print("deep structures") 260 local a = {} 261 for i = 1,200000 do 262 a = {next = a} 263 end 264 collectgarbage() 265 end 266 267 -- create many threads with self-references and open upvalues 268 local thread_id = 0 269 local threads = {} 270 271 function fn(thread) 272 local x = {} 273 threads[thread_id] = function() 274 thread = x 275 end 276 coroutine.yield() 277 end 278 279 while thread_id < 1000 do 280 local thread = coroutine.create(fn) 281 coroutine.resume(thread, thread) 282 thread_id = thread_id + 1 283 end 284 285 286 287 -- create a userdata to be collected when state is closed 288 do 289 local newproxy,assert,type,print,getmetatable = 290 newproxy,assert,type,print,getmetatable 291 local u = newproxy(true) 292 local tt = getmetatable(u) 293 ___Glob = {u} -- avoid udata being collected before program end 294 tt.__gc = function (o) 295 assert(getmetatable(o) == tt) 296 -- create new objects during GC 297 local a = 'xuxu'..(10+3)..'joao', {} 298 ___Glob = o -- ressurect object! 299 newproxy(o) -- creates a new one with same metatable 300 print(">>> closing state " .. "<<<\n") 301 end 302 end 303 304 -- create several udata to raise errors when collected while closing state 305 do 306 local u = newproxy(true) 307 getmetatable(u).__gc = function (o) return o + 1 end 308 table.insert(___Glob, u) -- preserve udata until the end 309 for i = 1,10 do table.insert(___Glob, newproxy(u)) end 310 end 311 312 print('OK')