Skip to content

Commit d1105c1

Browse files
committed
non-shrinking version of garbage collection
1 parent a1440f2 commit d1105c1

10 files changed

Lines changed: 61 additions & 39 deletions

README.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
- [Fragment Requirements](#fragment-requirements)
5656
- [Destruction Policies](#destruction-policies)
5757
- [Custom Component Storages](#custom-component-storages)
58+
- [Garbage Collection](#garbage-collection)
5859
- [Cheat Sheet](#cheat-sheet)
5960
- [Aliases](#aliases)
6061
- [Predefs](#predefs)
@@ -1346,6 +1347,24 @@ evolved.builder()
13461347
evolved.process_with(MOVEMENT_SYSTEM, 0.016)
13471348
```
13481349

1350+
### Garbage Collection
1351+
1352+
While using the library, some internal data structures can become obsolete and should be cleaned up to free memory. For example, empty chunks that no longer contain entities can be removed. Component storages can also have unused capacity that can be shrunk to save memory. The library provides a function to control this garbage collection process.
1353+
1354+
```lua
1355+
---@param no_shrink? boolean
1356+
function evolved.collect_garbage(no_shrink) end
1357+
```
1358+
1359+
By default, [`evolved.collect_garbage`](#evolvedcollect_garbage) cleans up obsolete data structures and shrinks component storages to fit their current size. If you pass `true`, it only cleans up obsolete data structures and skips shrinking. This avoids the overhead of resizing storages, which can be expensive.
1360+
1361+
Call this function periodically to keep memory usage under control. It is best to call it between levels or during loading screens when performance is not critical. Also, call Lua's built-in garbage collector afterward to ensure all unused memory is freed.
1362+
1363+
```lua
1364+
evolved.collect_garbage()
1365+
collectgarbage('collect')
1366+
```
1367+
13491368
## Cheat Sheet
13501369

13511370
### Aliases
@@ -1481,7 +1500,7 @@ process :: system... -> ()
14811500
process_with :: system, ... -> ()
14821501
14831502
debug_mode :: boolean -> ()
1484-
collect_garbage :: ()
1503+
collect_garbage :: boolean? -> ()
14851504
```
14861505

14871506
### Classes
@@ -2007,7 +2026,8 @@ function evolved.debug_mode(yesno) end
20072026
### `evolved.collect_garbage`
20082027

20092028
```lua
2010-
function evolved.collect_garbage() end
2029+
---@param no_shrink? boolean
2030+
function evolved.collect_garbage(no_shrink) end
20112031
```
20122032

20132033
## Classes

develop/ROADMAP.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
## Thoughts
1010

1111
- We should have a way to not copy components on deferred spawn/clone
12-
- Having a light version of the gargabe collector can be useful for some use-cases
1312
- Basic default component value as true looks awful, should we use something else?
1413

1514
## Known Issues

develop/fuzzing/batch_destroy_fuzz.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,11 @@ end
118118
---
119119

120120
if math.random(1, 2) == 1 then
121-
evo.collect_garbage()
121+
evo.collect_garbage(math.random(1, 2) == 1)
122122
end
123123

124124
evo.destroy(__table_unpack(all_entity_list))
125125

126126
if math.random(1, 2) == 1 then
127-
evo.collect_garbage()
127+
evo.collect_garbage(math.random(1, 2) == 1)
128128
end

develop/fuzzing/destroy_fuzz.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,11 @@ end
124124
---
125125

126126
if math.random(1, 2) == 1 then
127-
evo.collect_garbage()
127+
evo.collect_garbage(math.random(1, 2) == 1)
128128
end
129129

130130
evo.destroy(__table_unpack(all_entity_list))
131131

132132
if math.random(1, 2) == 1 then
133-
evo.collect_garbage()
133+
evo.collect_garbage(math.random(1, 2) == 1)
134134
end

develop/fuzzing/execute_fuzz.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -296,13 +296,13 @@ end
296296
---
297297

298298
if math.random(1, 2) == 1 then
299-
evo.collect_garbage()
299+
evo.collect_garbage(math.random(1, 2) == 1)
300300
end
301301

302302
evo.destroy(__table_unpack(all_query_list))
303303
evo.destroy(__table_unpack(all_entity_list))
304304
evo.destroy(__table_unpack(all_fragment_list))
305305

306306
if math.random(1, 2) == 1 then
307-
evo.collect_garbage()
307+
evo.collect_garbage(math.random(1, 2) == 1)
308308
end

develop/fuzzing/explicit_fuzz.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,11 @@ end
7878
---
7979

8080
if math.random(1, 2) == 1 then
81-
evo.collect_garbage()
81+
evo.collect_garbage(math.random(1, 2) == 1)
8282
end
8383

8484
evo.destroy(__table_unpack(all_entity_list))
8585

8686
if math.random(1, 2) == 1 then
87-
evo.collect_garbage()
87+
evo.collect_garbage(math.random(1, 2) == 1)
8888
end

develop/fuzzing/requires_fuzz.lua

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,17 +115,17 @@ end
115115
if math.random(1, 2) == 1 then
116116
evo.destroy(__table_unpack(all_entity_list))
117117
if math.random(1, 2) == 1 then
118-
evo.collect_garbage()
118+
evo.collect_garbage(math.random(1, 2) == 1)
119119
end
120120
evo.destroy(__table_unpack(all_fragment_list))
121121
else
122122
evo.destroy(__table_unpack(all_fragment_list))
123123
if math.random(1, 2) == 1 then
124-
evo.collect_garbage()
124+
evo.collect_garbage(math.random(1, 2) == 1)
125125
end
126126
evo.destroy(__table_unpack(all_entity_list))
127127
end
128128

129129
if math.random(1, 2) == 1 then
130-
evo.collect_garbage()
130+
evo.collect_garbage(math.random(1, 2) == 1)
131131
end

develop/fuzzing/unique_fuzz.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,11 +64,11 @@ end
6464
---
6565

6666
if math.random(1, 2) == 1 then
67-
evo.collect_garbage()
67+
evo.collect_garbage(math.random(1, 2) == 1)
6868
end
6969

7070
evo.destroy(__table_unpack(all_entity_list))
7171

7272
if math.random(1, 2) == 1 then
73-
evo.collect_garbage()
73+
evo.collect_garbage(math.random(1, 2) == 1)
7474
end

evolved.d.tl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@
212212
process_with: function(system: System, ...: any)
213213

214214
debug_mode: function(yesno: boolean)
215-
collect_garbage: function()
215+
collect_garbage: function(no_shrink?: boolean)
216216

217217
chunk: function(fragment: Fragment, ...: Fragment): Chunk, { Entity }, integer
218218
builder: function(): Builder

evolved.lua

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6145,7 +6145,8 @@ function __evolved_debug_mode(yesno)
61456145
__debug_mode = yesno
61466146
end
61476147

6148-
function __evolved_collect_garbage()
6148+
---@param no_shrink boolean?
6149+
function __evolved_collect_garbage(no_shrink)
61496150
if __defer_depth > 0 then
61506151
__defer_call_hook(__evolved_collect_garbage)
61516152
return
@@ -6209,16 +6210,16 @@ function __evolved_collect_garbage()
62096210
local postorder_chunk_entity_count = postorder_chunk.__entity_count
62106211
local postorder_chunk_entity_capacity = postorder_chunk.__entity_capacity
62116212

6212-
local should_be_purged =
6213+
local can_be_purged =
62136214
postorder_chunk_child_count == 0 and
62146215
postorder_chunk_entity_count == 0
62156216

6216-
local should_be_shrunk =
6217+
local can_be_shrunk =
62176218
postorder_chunk_entity_count < postorder_chunk_entity_capacity
62186219

6219-
if should_be_purged then
6220+
if can_be_purged then
62206221
__purge_chunk(postorder_chunk)
6221-
elseif should_be_shrunk then
6222+
elseif can_be_shrunk and not no_shrink then
62226223
__shrink_chunk(postorder_chunk, 0)
62236224
end
62246225
end
@@ -6234,29 +6235,31 @@ function __evolved_collect_garbage()
62346235
end
62356236
end
62366237

6237-
for table_pool_tag = 1, __table_pool_tag.__count do
6238-
local table_pool_reserve = __table_pool_reserve[table_pool_tag]
6238+
if not no_shrink then
6239+
for table_pool_tag = 1, __table_pool_tag.__count do
6240+
local table_pool_reserve = __table_pool_reserve[table_pool_tag]
62396241

6240-
---@type evolved.table_pool
6241-
local new_table_pool = __lua_table_new(table_pool_reserve)
6242+
---@type evolved.table_pool
6243+
local new_table_pool = __lua_table_new(table_pool_reserve)
62426244

6243-
for table_pool_index = 1, table_pool_reserve do
6244-
new_table_pool[table_pool_index] = {}
6245-
end
6245+
for table_pool_index = 1, table_pool_reserve do
6246+
new_table_pool[table_pool_index] = {}
6247+
end
62466248

6247-
new_table_pool.__size = table_pool_reserve
6249+
new_table_pool.__size = table_pool_reserve
62486250

6249-
__tagged_table_pools[table_pool_tag] = new_table_pool
6250-
end
6251+
__tagged_table_pools[table_pool_tag] = new_table_pool
6252+
end
62516253

6252-
do
6253-
__entity_chunks = __table_dup(__entity_chunks)
6254-
__entity_places = __table_dup(__entity_places)
6255-
end
6254+
do
6255+
__entity_chunks = __table_dup(__entity_chunks)
6256+
__entity_places = __table_dup(__entity_places)
6257+
end
62566258

6257-
do
6258-
__defer_points = __list_dup(__defer_points, __defer_depth)
6259-
__defer_bytecode = __list_dup(__defer_bytecode, __defer_length)
6259+
do
6260+
__defer_points = __list_dup(__defer_points, __defer_depth)
6261+
__defer_bytecode = __list_dup(__defer_bytecode, __defer_length)
6262+
end
62606263
end
62616264

62626265
__evolved_commit()

0 commit comments

Comments
 (0)