gc.lua 6.8 KB

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