github.com/hirochachacha/plua@v0.0.0-20170217012138-c82f520cc725/testdata/lua-5.3.3-tests/gc.lua (about) 1 -- $Id: gc.lua,v 1.71 2016/03/07 19:31:35 roberto Exp $ 2 3 print('testing garbage collection') 4 5 local debug = require"debug" 6 7 collectgarbage() 8 9 assert(collectgarbage("isrunning")) 10 11 local function gcinfo () return collectgarbage"count" * 1024 end 12 13 -- test weird parameters 14 -- do 15 -- -- save original parameters 16 -- local a = collectgarbage("setpause", 200) 17 -- local b = collectgarbage("setstepmul", 200) 18 -- local t = {0, 2, 10, 90, 500, 5000, 30000, 0x7ffffffe} 19 -- for i = 1, #t do 20 -- local p = t[i] 21 -- for j = 1, #t do 22 -- local m = t[j] 23 -- collectgarbage("setpause", p) 24 -- collectgarbage("setstepmul", m) 25 -- collectgarbage("step", 0) 26 -- collectgarbage("step", 10000) 27 -- end 28 -- end 29 -- -- restore original parameters 30 -- collectgarbage("setpause", a) 31 -- collectgarbage("setstepmul", b) 32 -- collectgarbage() 33 -- end 34 35 36 _G["while"] = 234 37 38 limit = 5000 39 40 41 local function GC1 () 42 local u 43 local b -- must be declared after 'u' (to be above it in the stack) 44 local finish = false 45 u = setmetatable({}, {__gc = function () finish = true end}) 46 b = {34} 47 repeat u = {} until finish 48 assert(b[1] == 34) -- 'u' was collected, but 'b' was not 49 50 finish = false; local i = 1 51 u = setmetatable({}, {__gc = function () finish = true end}) 52 repeat i = i + 1; u = tostring(i) .. tostring(i) until finish 53 assert(b[1] == 34) -- 'u' was collected, but 'b' was not 54 55 finish = false 56 u = setmetatable({}, {__gc = function () finish = true end}) 57 repeat local i; u = function () return i end until finish 58 assert(b[1] == 34) -- 'u' was collected, but 'b' was not 59 end 60 61 local function GC2 () 62 local u 63 local finish = false 64 u = {setmetatable({}, {__gc = function () finish = true end})} 65 b = {34} 66 repeat u = {{}} until finish 67 assert(b[1] == 34) -- 'u' was collected, but 'b' was not 68 69 finish = false; local i = 1 70 u = {setmetatable({}, {__gc = function () finish = true end})} 71 repeat i = i + 1; u = {tostring(i) .. tostring(i)} until finish 72 assert(b[1] == 34) -- 'u' was collected, but 'b' was not 73 74 finish = false 75 u = {setmetatable({}, {__gc = function () finish = true end})} 76 repeat local i; u = {function () return i end} until finish 77 assert(b[1] == 34) -- 'u' was collected, but 'b' was not 78 end 79 80 local function GC() GC1(); GC2() end 81 82 83 contCreate = 0 84 85 print('tables') 86 while contCreate <= limit do 87 local a = {}; a = nil 88 contCreate = contCreate+1 89 end 90 91 a = "a" 92 93 contCreate = 0 94 print('strings') 95 while contCreate <= limit do 96 a = contCreate .. "b"; 97 a = string.gsub(a, '(%d%d*)', string.upper) 98 a = "a" 99 contCreate = contCreate+1 100 end 101 102 103 contCreate = 0 104 105 a = {} 106 107 print('functions') 108 function a:test () 109 while contCreate <= limit do 110 load(string.format("function temp(a) return 'a%d' end", contCreate), "")() 111 assert(temp() == string.format('a%d', contCreate)) 112 contCreate = contCreate+1 113 end 114 end 115 116 a:test() 117 118 -- collection of functions without locals, globals, etc. 119 do local f = function () end end 120 121 122 print("functions with errors") 123 prog = [[ 124 do 125 a = 10; 126 function foo(x,y) 127 a = sin(a+0.456-0.23e-12); 128 return function (z) return sin(%x+z) end 129 end 130 local x = function (w) a=a+w; end 131 end 132 ]] 133 do 134 local step = 1 135 if _soft then step = 13 end 136 for i=1, string.len(prog), step do 137 for j=i, string.len(prog), step do 138 pcall(load(string.sub(prog, i, j), "")) 139 end 140 end 141 end 142 143 foo = nil 144 print('long strings') 145 x = "01234567890123456789012345678901234567890123456789012345678901234567890123456789" 146 assert(string.len(x)==80) 147 s = '' 148 n = 0 149 k = math.min(300, (math.maxinteger // 80) // 2) 150 while n < k do s = s..x; n=n+1; j=tostring(n) end 151 assert(string.len(s) == k*80) 152 s = string.sub(s, 1, 10000) 153 s, i = string.gsub(s, '(%d%d%d%d)', '') 154 assert(i==10000 // 4) 155 s = nil 156 x = nil 157 158 assert(_G["while"] == 234) 159 160 161 print("steps") 162 163 print("steps (2)") 164 165 local function dosteps (siz) 166 assert(not collectgarbage("isrunning")) 167 collectgarbage() 168 assert(not collectgarbage("isrunning")) 169 local a = {} 170 for i=1,100 do a[i] = {{}}; local b = {} end 171 local x = gcinfo() 172 local i = 0 173 repeat -- do steps until it completes a collection cycle 174 i = i+1 175 until collectgarbage("step", siz) 176 assert(gcinfo() < x) 177 return i 178 end 179 180 -- collectgarbage"stop" 181 182 if not _port then 183 -- test the "size" of basic GC steps (whatever they mean...) 184 assert(dosteps(0) > 10) 185 assert(dosteps(10) < dosteps(2)) 186 end 187 188 -- collector should do a full collection with so many steps 189 -- assert(dosteps(20000) == 1) 190 -- assert(collectgarbage("step", 20000) == true) 191 -- assert(collectgarbage("step", 20000) == true) 192 193 -- assert(not collectgarbage("isrunning")) 194 -- collectgarbage"restart" 195 -- assert(collectgarbage("isrunning")) 196 197 198 if not _port then 199 -- test the pace of the collector 200 collectgarbage(); collectgarbage() 201 local x = gcinfo() 202 collectgarbage"stop" 203 assert(not collectgarbage("isrunning")) 204 repeat 205 local a = {} 206 until gcinfo() > 3 * x 207 collectgarbage"restart" 208 assert(collectgarbage("isrunning")) 209 repeat 210 local a = {} 211 until gcinfo() <= x * 2 212 end 213 214 215 print("clearing tables") 216 lim = 15 217 a = {} 218 -- fill a with `collectable' indices 219 for i=1,lim do a[{}] = i end 220 b = {} 221 for k,v in pairs(a) do b[k]=v end 222 -- remove all indices and collect them 223 for n in pairs(b) do 224 a[n] = nil 225 assert(type(n) == 'table' and next(n) == nil) 226 collectgarbage() 227 end 228 b = nil 229 collectgarbage() 230 for n in pairs(a) do error'cannot be here' end 231 for i=1,lim do a[i] = i end 232 for i=1,lim do assert(a[i] == i) end 233 234 235 -- print('weak tables') 236 -- a = {}; setmetatable(a, {__mode = 'k'}); 237 -- -- fill a with some `collectable' indices 238 -- for i=1,lim do a[{}] = i end 239 -- -- and some non-collectable ones 240 -- for i=1,lim do a[i] = i end 241 -- for i=1,lim do local s=string.rep('@', i); a[s] = s..'#' end 242 -- collectgarbage() 243 -- local i = 0 244 -- for k,v in pairs(a) do assert(k==v or k..'#'==v); i=i+1 end 245 -- assert(i == 2*lim) 246 247 -- a = {}; setmetatable(a, {__mode = 'v'}); 248 -- a[1] = string.rep('b', 21) 249 -- collectgarbage() 250 -- assert(a[1]) -- strings are *values* 251 -- a[1] = nil 252 -- -- fill a with some `collectable' values (in both parts of the table) 253 -- for i=1,lim do a[i] = {} end 254 -- for i=1,lim do a[i..'x'] = {} end 255 -- -- and some non-collectable ones 256 -- for i=1,lim do local t={}; a[t]=t end 257 -- for i=1,lim do a[i+lim]=i..'x' end 258 -- collectgarbage() 259 -- local i = 0 260 -- for k,v in pairs(a) do assert(k==v or k-lim..'x' == v); i=i+1 end 261 -- assert(i == 2*lim) 262 263 -- a = {}; setmetatable(a, {__mode = 'vk'}); 264 -- local x, y, z = {}, {}, {} 265 -- -- keep only some items 266 -- a[1], a[2], a[3] = x, y, z 267 -- a[string.rep('$', 11)] = string.rep('$', 11) 268 -- -- fill a with some `collectable' values 269 -- for i=4,lim do a[i] = {} end 270 -- for i=1,lim do a[{}] = i end 271 -- for i=1,lim do local t={}; a[t]=t end 272 -- collectgarbage() 273 -- assert(next(a) ~= nil) 274 -- local i = 0 275 -- for k,v in pairs(a) do 276 -- assert((k == 1 and v == x) or 277 -- (k == 2 and v == y) or 278 -- (k == 3 and v == z) or k==v); 279 -- i = i+1 280 -- end 281 -- assert(i == 4) 282 -- x,y,z=nil 283 -- collectgarbage() 284 -- assert(next(a) == string.rep('$', 11)) 285 286 287 -- 'bug' in 5.1 288 -- a = {} 289 -- local t = {x = 10} 290 -- local C = setmetatable({key = t}, {__mode = 'v'}) 291 -- local C1 = setmetatable({[t] = 1}, {__mode = 'k'}) 292 -- a.x = t -- this should not prevent 't' from being removed from 293 -- -- weak table 'C' by the time 'a' is finalized 294 295 -- setmetatable(a, {__gc = function (u) 296 -- assert(C.key == nil) 297 -- assert(type(next(C1)) == 'table') 298 -- end}) 299 300 -- a, t = nil 301 -- collectgarbage() 302 -- collectgarbage() 303 -- assert(next(C) == nil and next(C1) == nil) 304 -- C, C1 = nil 305 306 307 -- -- ephemerons 308 -- local mt = {__mode = 'k'} 309 -- a = {{10},{20},{30},{40}}; setmetatable(a, mt) 310 -- x = nil 311 -- for i = 1, 100 do local n = {}; a[n] = {k = {x}}; x = n end 312 -- GC() 313 -- local n = x 314 -- local i = 0 315 -- while n do n = a[n].k[1]; i = i + 1 end 316 -- assert(i == 100) 317 -- x = nil 318 -- GC() 319 -- for i = 1, 4 do assert(a[i][1] == i * 10); a[i] = nil end 320 -- assert(next(a) == nil) 321 322 -- local K = {} 323 -- a[K] = {} 324 -- for i=1,10 do a[K][i] = {}; a[a[K][i]] = setmetatable({}, mt) end 325 -- x = nil 326 -- local k = 1 327 -- for j = 1,100 do 328 -- local n = {}; local nk = k%10 + 1 329 -- a[a[K][nk]][n] = {x, k = k}; x = n; k = nk 330 -- end 331 -- GC() 332 -- local n = x 333 -- local i = 0 334 -- while n do local t = a[a[K][k]][n]; n = t[1]; k = t.k; i = i + 1 end 335 -- assert(i == 100) 336 -- K = nil 337 -- GC() 338 -- -- assert(next(a) == nil) 339 340 341 -- -- testing errors during GC 342 -- do 343 -- collectgarbage("stop") -- stop collection 344 -- local u = {} 345 -- local s = {}; setmetatable(s, {__mode = 'k'}) 346 -- setmetatable(u, {__gc = function (o) 347 -- local i = s[o] 348 -- s[i] = true 349 -- assert(not s[i - 1]) -- check proper finalization order 350 -- if i == 8 then error("here") end -- error during GC 351 -- end}) 352 353 -- for i = 6, 10 do 354 -- local n = setmetatable({}, getmetatable(u)) 355 -- s[n] = i 356 -- end 357 358 -- assert(not pcall(collectgarbage)) 359 -- for i = 8, 10 do assert(s[i]) end 360 361 -- for i = 1, 5 do 362 -- local n = setmetatable({}, getmetatable(u)) 363 -- s[n] = i 364 -- end 365 366 -- collectgarbage() 367 -- for i = 1, 10 do assert(s[i]) end 368 369 -- getmetatable(u).__gc = false 370 371 372 -- -- __gc errors with non-string messages 373 -- setmetatable({}, {__gc = function () error{} end}) 374 -- local a, b = pcall(collectgarbage) 375 -- assert(not a and type(b) == "string" and string.find(b, "error in __gc")) 376 377 -- end 378 -- print '+' 379 380 381 -- -- testing userdata 382 -- if T==nil then 383 -- (Message or print)('\n >>> testC not active: skipping userdata GC tests <<<\n') 384 385 -- else 386 387 -- local function newproxy(u) 388 -- return debug.setmetatable(T.newuserdata(0), debug.getmetatable(u)) 389 -- end 390 391 -- collectgarbage("stop") -- stop collection 392 -- local u = newproxy(nil) 393 -- debug.setmetatable(u, {__gc = true}) 394 -- local s = 0 395 -- local a = {[u] = 0}; setmetatable(a, {__mode = 'vk'}) 396 -- for i=1,10 do a[newproxy(u)] = i end 397 -- for k in pairs(a) do assert(getmetatable(k) == getmetatable(u)) end 398 -- local a1 = {}; for k,v in pairs(a) do a1[k] = v end 399 -- for k,v in pairs(a1) do a[v] = k end 400 -- for i =1,10 do assert(a[i]) end 401 -- getmetatable(u).a = a1 402 -- getmetatable(u).u = u 403 -- do 404 -- local u = u 405 -- getmetatable(u).__gc = function (o) 406 -- assert(a[o] == 10-s) 407 -- assert(a[10-s] == nil) -- udata already removed from weak table 408 -- assert(getmetatable(o) == getmetatable(u)) 409 -- assert(getmetatable(o).a[o] == 10-s) 410 -- s=s+1 411 -- end 412 -- end 413 -- a1, u = nil 414 -- assert(next(a) ~= nil) 415 -- collectgarbage() 416 -- assert(s==11) 417 -- collectgarbage() 418 -- assert(next(a) == nil) -- finalized keys are removed in two cycles 419 -- end 420 421 422 -- -- __gc x weak tables 423 -- local u = setmetatable({}, {__gc = true}) 424 -- -- __gc metamethod should be collected before running 425 -- setmetatable(getmetatable(u), {__mode = "v"}) 426 -- getmetatable(u).__gc = function (o) os.exit(1) end -- cannot happen 427 -- u = nil 428 -- collectgarbage() 429 430 -- local u = setmetatable({}, {__gc = true}) 431 -- local m = getmetatable(u) 432 -- m.x = {[{0}] = 1; [0] = {1}}; setmetatable(m.x, {__mode = "kv"}); 433 -- m.__gc = function (o) 434 -- assert(next(getmetatable(o).x) == nil) 435 -- m = 10 436 -- end 437 -- u, m = nil 438 -- collectgarbage() 439 -- assert(m==10) 440 441 442 -- -- errors during collection 443 -- u = setmetatable({}, {__gc = function () error "!!!" end}) 444 -- u = nil 445 -- assert(not pcall(collectgarbage)) 446 447 448 -- if not _soft then 449 -- print("deep structures") 450 -- local a = {} 451 -- for i = 1,200000 do 452 -- a = {next = a} 453 -- end 454 -- collectgarbage() 455 -- end 456 457 -- -- create many threads with self-references and open upvalues 458 -- print("self-referenced threads") 459 -- local thread_id = 0 460 -- local threads = {} 461 462 -- local function fn (thread) 463 -- local x = {} 464 -- threads[thread_id] = function() 465 -- thread = x 466 -- end 467 -- coroutine.yield() 468 -- end 469 470 -- while thread_id < 1000 do 471 -- local thread = coroutine.create(fn) 472 -- coroutine.resume(thread, thread) 473 -- thread_id = thread_id + 1 474 -- end 475 476 477 -- -- Create a closure (function inside 'f') with an upvalue ('param') that 478 -- -- points (through a table) to the closure itself and to the thread 479 -- -- ('co' and the initial value of 'param') where closure is running. 480 -- -- Then, assert that table (and therefore everything else) will be 481 -- -- collected. 482 -- do 483 -- local collected = false -- to detect collection 484 -- collectgarbage(); collectgarbage("stop") 485 -- do 486 -- local function f (param) 487 -- ;(function () 488 -- assert(type(f) == 'function' and type(param) == 'thread') 489 -- param = {param, f} 490 -- setmetatable(param, {__gc = function () collected = true end}) 491 -- coroutine.yield(100) 492 -- end)() 493 -- end 494 -- local co = coroutine.create(f) 495 -- assert(coroutine.resume(co, co)) 496 -- end 497 -- -- Now, thread and closure are not reacheable any more; 498 -- -- two collections are needed to break cycle 499 -- collectgarbage() 500 -- assert(not collected) 501 -- collectgarbage() 502 -- assert(collected) 503 -- collectgarbage("restart") 504 -- end 505 506 507 -- do 508 -- collectgarbage() 509 -- collectgarbage"stop" 510 -- local x = gcinfo() 511 -- repeat 512 -- for i=1,1000 do _ENV.a = {} end 513 -- collectgarbage("step", 0) -- steps should not unblock the collector 514 -- until gcinfo() > 2 * x 515 -- collectgarbage"restart" 516 -- end 517 518 519 -- if T then -- tests for weird cases collecting upvalues 520 521 -- local function foo () 522 -- local a = {x = 20} 523 -- coroutine.yield(function () return a.x end) -- will run collector 524 -- assert(a.x == 20) -- 'a' is 'ok' 525 -- a = {x = 30} -- create a new object 526 -- assert(T.gccolor(a) == "white") -- of course it is new... 527 -- coroutine.yield(100) -- 'a' is still local to this thread 528 -- end 529 530 -- local t = setmetatable({}, {__mode = "kv"}) 531 -- collectgarbage(); collectgarbage('stop') 532 -- -- create coroutine in a weak table, so it will never be marked 533 -- t.co = coroutine.wrap(foo) 534 -- local f = t.co() -- create function to access local 'a' 535 -- T.gcstate("atomic") -- ensure all objects are traversed 536 -- assert(T.gcstate() == "atomic") 537 -- assert(t.co() == 100) -- resume coroutine, creating new table for 'a' 538 -- assert(T.gccolor(t.co) == "white") -- thread was not traversed 539 -- T.gcstate("pause") -- collect thread, but should mark 'a' before that 540 -- assert(t.co == nil and f() == 30) -- ensure correct access to 'a' 541 542 -- collectgarbage("restart") 543 544 -- -- test barrier in sweep phase (advance cleaning of upvalue to white) 545 -- local u = T.newuserdata(0) -- create a userdata 546 -- collectgarbage() 547 -- collectgarbage"stop" 548 -- T.gcstate"atomic" 549 -- T.gcstate"sweepallgc" 550 -- local x = {} 551 -- assert(T.gccolor(u) == "black") -- upvalue is "old" (black) 552 -- assert(T.gccolor(x) == "white") -- table is "new" (white) 553 -- debug.setuservalue(u, x) -- trigger barrier 554 -- assert(T.gccolor(u) == "white") -- upvalue changed to white 555 -- collectgarbage"restart" 556 557 -- print"+" 558 -- end 559 560 561 -- if T then 562 -- local debug = require "debug" 563 -- collectgarbage("stop") 564 -- local x = T.newuserdata(0) 565 -- local y = T.newuserdata(0) 566 -- debug.setmetatable(y, {__gc = true}) -- bless the new udata before... 567 -- debug.setmetatable(x, {__gc = true}) -- ...the old one 568 -- assert(T.gccolor(y) == "white") 569 -- T.checkmemory() 570 -- collectgarbage("restart") 571 -- end 572 573 574 -- if T then 575 -- print("emergency collections") 576 -- collectgarbage() 577 -- collectgarbage() 578 -- T.totalmem(T.totalmem() + 200) 579 -- for i=1,200 do local a = {} end 580 -- T.totalmem(0) 581 -- collectgarbage() 582 -- local t = T.totalmem("table") 583 -- local a = {{}, {}, {}} -- create 4 new tables 584 -- assert(T.totalmem("table") == t + 4) 585 -- t = T.totalmem("function") 586 -- a = function () end -- create 1 new closure 587 -- assert(T.totalmem("function") == t + 1) 588 -- t = T.totalmem("thread") 589 -- a = coroutine.create(function () end) -- create 1 new coroutine 590 -- assert(T.totalmem("thread") == t + 1) 591 -- end 592 593 -- -- create an object to be collected when state is closed 594 -- do 595 -- local setmetatable,assert,type,print,getmetatable = 596 -- setmetatable,assert,type,print,getmetatable 597 -- local tt = {} 598 -- tt.__gc = function (o) 599 -- assert(getmetatable(o) == tt) 600 -- -- create new objects during GC 601 -- local a = 'xuxu'..(10+3)..'joao', {} 602 -- ___Glob = o -- ressurect object! 603 -- setmetatable({}, tt) -- creates a new one with same metatable 604 -- print(">>> closing state " .. "<<<\n") 605 -- end 606 -- local u = setmetatable({}, tt) 607 -- ___Glob = {u} -- avoid object being collected before program end 608 -- end 609 610 -- -- create several objects to raise errors when collected while closing state 611 -- do 612 -- local mt = {__gc = function (o) return o + 1 end} 613 -- for i = 1,10 do 614 -- -- create object and preserve it until the end 615 -- table.insert(___Glob, setmetatable({}, mt)) 616 -- end 617 -- end 618 619 -- just to make sure 620 assert(collectgarbage'isrunning') 621 622 print('OK')