github.com/guardangely/gopher-lua@v0.0.0-20200324075529-f92e6f279f59/_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')