aboutsummaryrefslogtreecommitdiffhomepage
path: root/notes/garbage_collection.txt
blob: 62efb63d161c13ae512c633f4c7edf5aa8eafa70 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95

Garbage collection
==================

There are three types of memory leaks with arenas:
1. Unused tail parts of blocks.
2. Items that are no longer reachable.
3. Items that can't possibly be accessed in any reachable code path.
   (I don't think this is very well researched, so I will ignore this type)

There are at least 4 alternative solutions for handling leak types 1 & 2:

* Do nothing
* Put tail parts in a free-list and try to re-use whenever an arena is full.
* Conservative garbage collection
    - Needs to know the size of each alloc'n. This info can be packed/batched
      into words (e.g. 5*12 <= 64 for 4096 byte blocks on 64 bit platforms)
    - Does not solve the tail-parts problem
    - Can be DoS'ed by putting valid memory addresses in integers.
    - Can be used to leak memory addresses by adding lots of integers
      and measuring the memory usage after garbage collection.
* Compacting garbage collection
    - Needs to know the size of each allocation.
    - Needs to know where pointers in each allocation are.
        - Can store type info
        - Can store a bitmask.
        - Combining these two, for 4096 byte arenas:
            12 bits size + 1 bit mode + 51 bits type type info / bitmask
            51 bits = 408 bytes max.
        - I think that 408 bytes large objects WITH pointers are fairly
          uncommon, so perhaps we could use only bitmasks:
            12 bits size + 51 bits bitmask + 1 bit more-bitmasks-present
            optional: 63 bits bitmask + 1 bit more-bitmasks-present (up to 8)
        - Put this info before each allocataion? Or last?
          Some platforms will require alignment.
        - Apparently, OpenJDK puts all outgoing pointers first,
          so they just need a "number of outgoing pointers" field.
          (This would not work in SLUL, which needs structs with stable
           ordering of fields)
* Root-type-aware garbage collection
    - SLUL does not have variant types, so in theory, it could be possible
      to track only the types of the "roots" (i.e. references from local
      variables/function parameters).
    - Maybe this could use debugging information somehow?
      Or perhaps store the info in a special-purpose section?
        - It can be stored as code or data.
        - With code, it can trivially call code across libraries.
          But there is a performance penalty per call.
        - With data, the runtime could list all loaded/mapped modules,
          and then scan the ELF/PE header of each of them to find the
          GC meta-data. The runtime would have to bind all cross-module
          references in the meta-data. The initialization has to be done
          only once per process (or again if modules are loaded or unloaded
          at runtime).
    - But there are "slot" types / type parameters!
      I *think* that those could be determined from the stack trace,
      at least somewhere the type parameters <T,U,..> will have known
      values if you go far towards main() enough.
    - With known types, the size as well as the offsets to outbound
      references become known. (Plus any nested structs/arrays)
    - The GC could be enabled per-thread / per-arena.
        - This way, the garbage collection only needs to stop one thread
        - And "garbage" can be isolated to requests/users/etc. to give
          some form of resource control, so one user cannot slow down
          garbage collection for others.
        - It would have to track which arenas can have outbound/inbound
          references to each other.

Object categories
-----------------

It might be useful to categorize allocations as follows:

- has/lacks outgoing pointers.
- has/lacks outgoing mutable pointers.
- might have/lacks incoming interior pointers.
- might have/lacks incoming pointers from the heap.

Compacting GC for arenas
------------------------

Where to put the meta-data?
* in-line, before/after each allocation?
  how should this interact with alignment?
* in a separate memory area? (bump-allocated?)

Metadata bytes:

first byte 0-127:   pointer-free short block
first byte 128-255: other kind of block (bitmask):
    bit 6   -   contains pointers.
    bit 0-5 -   length (63 = long length)
long length
pointer locations (bitmask? on/off run-length encoding?)

Or perhaps store pointers to type information?