gengc.lua 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. -- $Id: testes/gengc.lua $
  2. -- See Copyright Notice in file lua.h
  3. print('testing generational garbage collection')
  4. local debug = require"debug"
  5. assert(collectgarbage("isrunning"))
  6. collectgarbage()
  7. local oldmode = collectgarbage("generational")
  8. -- ensure that table barrier evolves correctly
  9. do
  10. local U = {}
  11. -- full collection makes 'U' old
  12. collectgarbage()
  13. assert(not T or T.gcage(U) == "old")
  14. -- U refers to a new table, so it becomes 'touched1'
  15. U[1] = {x = {234}}
  16. assert(not T or (T.gcage(U) == "touched1" and T.gcage(U[1]) == "new"))
  17. -- both U and the table survive one more collection
  18. collectgarbage("step")
  19. assert(not T or (T.gcage(U) == "touched2" and T.gcage(U[1]) == "survival"))
  20. -- both U and the table survive yet another collection
  21. -- now everything is old
  22. collectgarbage("step")
  23. assert(not T or (T.gcage(U) == "old" and T.gcage(U[1]) == "old1"))
  24. -- data was not corrupted
  25. assert(U[1].x[1] == 234)
  26. end
  27. do
  28. -- ensure that 'firstold1' is corrected when object is removed from
  29. -- the 'allgc' list
  30. local function foo () end
  31. local old = {10}
  32. collectgarbage() -- make 'old' old
  33. assert(not T or T.gcage(old) == "old")
  34. setmetatable(old, {}) -- new table becomes OLD0 (barrier)
  35. assert(not T or T.gcage(getmetatable(old)) == "old0")
  36. collectgarbage("step") -- new table becomes OLD1 and firstold1
  37. assert(not T or T.gcage(getmetatable(old)) == "old1")
  38. setmetatable(getmetatable(old), {__gc = foo}) -- get it out of allgc list
  39. collectgarbage("step") -- should not seg. fault
  40. end
  41. do -- bug in 5.4.0
  42. -- When an object aged OLD1 is finalized, it is moved from the list
  43. -- 'finobj' to the *beginning* of the list 'allgc', but that part of the
  44. -- list was not being visited by 'markold'.
  45. local A = {}
  46. A[1] = false -- old anchor for object
  47. -- obj finalizer
  48. local function gcf (obj)
  49. A[1] = obj -- anchor object
  50. assert(not T or T.gcage(obj) == "old1")
  51. obj = nil -- remove it from the stack
  52. collectgarbage("step") -- do a young collection
  53. print(getmetatable(A[1]).x) -- metatable was collected
  54. end
  55. collectgarbage() -- make A old
  56. local obj = {} -- create a new object
  57. collectgarbage("step") -- make it a survival
  58. assert(not T or T.gcage(obj) == "survival")
  59. setmetatable(obj, {__gc = gcf, x = "+"}) -- create its metatable
  60. assert(not T or T.gcage(getmetatable(obj)) == "new")
  61. obj = nil -- clear object
  62. collectgarbage("step") -- will call obj's finalizer
  63. end
  64. do -- another bug in 5.4.0
  65. local old = {10}
  66. collectgarbage() -- make 'old' old
  67. local co = coroutine.create(
  68. function ()
  69. local x = nil
  70. local f = function ()
  71. return x[1]
  72. end
  73. x = coroutine.yield(f)
  74. coroutine.yield()
  75. end
  76. )
  77. local _, f = coroutine.resume(co) -- create closure over 'x' in coroutine
  78. collectgarbage("step") -- make upvalue a survival
  79. old[1] = {"hello"} -- 'old' go to grayagain as 'touched1'
  80. coroutine.resume(co, {123}) -- its value will be new
  81. co = nil
  82. collectgarbage("step") -- hit the barrier
  83. assert(f() == 123 and old[1][1] == "hello")
  84. collectgarbage("step") -- run the collector once more
  85. -- make sure old[1] was not collected
  86. assert(f() == 123 and old[1][1] == "hello")
  87. end
  88. do -- bug introduced in commit 9cf3299fa
  89. local t = setmetatable({}, {__mode = "kv"}) -- all-weak table
  90. collectgarbage() -- full collection
  91. assert(not T or T.gcage(t) == "old")
  92. t[1] = {10}
  93. assert(not T or (T.gcage(t) == "touched1" and T.gccolor(t) == "gray"))
  94. collectgarbage("step") -- minor collection
  95. assert(not T or (T.gcage(t) == "touched2" and T.gccolor(t) == "black"))
  96. collectgarbage("step") -- minor collection
  97. assert(not T or T.gcage(t) == "old") -- t should be black, but it was gray
  98. t[1] = {10} -- no barrier here, so t was still old
  99. collectgarbage("step") -- minor collection
  100. -- t, being old, is ignored by the collection, so it is not cleared
  101. assert(t[1] == nil) -- fails with the bug
  102. end
  103. if T == nil then
  104. (Message or print)('\n >>> testC not active: \z
  105. skipping some generational tests <<<\n')
  106. print 'OK'
  107. return
  108. end
  109. -- ensure that userdata barrier evolves correctly
  110. do
  111. local U = T.newuserdata(0, 1)
  112. -- full collection makes 'U' old
  113. collectgarbage()
  114. assert(T.gcage(U) == "old")
  115. -- U refers to a new table, so it becomes 'touched1'
  116. debug.setuservalue(U, {x = {234}})
  117. assert(T.gcage(U) == "touched1" and
  118. T.gcage(debug.getuservalue(U)) == "new")
  119. -- both U and the table survive one more collection
  120. collectgarbage("step")
  121. assert(T.gcage(U) == "touched2" and
  122. T.gcage(debug.getuservalue(U)) == "survival")
  123. -- both U and the table survive yet another collection
  124. -- now everything is old
  125. collectgarbage("step")
  126. assert(T.gcage(U) == "old" and
  127. T.gcage(debug.getuservalue(U)) == "old1")
  128. -- data was not corrupted
  129. assert(debug.getuservalue(U).x[1] == 234)
  130. end
  131. -- just to make sure
  132. assert(collectgarbage'isrunning')
  133. do print"testing stop-the-world collection"
  134. local step = collectgarbage("param", "stepsize", 0);
  135. collectgarbage("incremental")
  136. assert(collectgarbage("param", "stepsize") == 0)
  137. -- each step does a complete cycle
  138. assert(collectgarbage("step"))
  139. assert(collectgarbage("step"))
  140. -- back to default value
  141. collectgarbage("param", "stepsize", step);
  142. assert(collectgarbage("param", "stepsize") == step)
  143. end
  144. collectgarbage(oldmode)
  145. print('OK')