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