Some new ideas.
[bpt/guile.git] / devel / memory.text
CommitLineData
2e203f2d
MV
1The following is gathered from a shortish discussion on the
2guile-devel mailing list. I plan to implement this in the next
3days. -mvo
4
5Improving memory handling in Guile
6----------------------------------
7
8I think we have a problem with the `mallocated' GC trigger. It is not
9maintained reliably and I'm afraid we need to have everybody review
10their code to get it right.
11
12I think the current interface with scm_must_malloc, scm_must_free,
13scm_done_malloc, scm_done_free is too difficult to use right and too
14hard to debug.
15
16Guile itself is full of mtrigger related bugs, I'm afraid. A typical
17one is in fports.c: the buffers for a fport are allocated with
18scm_must_malloc and freed with scm_must_free. The allocation is
19reported to the GC, but the freeing never is. The result is that the
20GC thinks that more and more memory is being allocated that it should
21be able to free, but that never actually gets freed (although in
22reality the program is very well behaved). As a counter measure to
23constant GC, the GC raises its mtrigger setting in a frenzy until it
24wraps around, causing a `hallucinating GC' syndrome, effectively
25stopping the program dead.
26
27(Watch scm_mtrigger while your favorite long-running Guile program
28executes, it will continuously rise.)
29
30The problem is that scm_must_malloc registers the allocated amount
31with the GC, but scm_must_free does not de-register it. For that, one
32would currently needs to use scm_done_free, or return an appropriate
33number from a smob free routine.
34
35Another problem is that scm_must_malloc is used in places where it is
36probably not appropriate since the caller does not know whether that
37block memory is really ending up under the control of the GC, or not.
38For example scm_do_read_line in rdelim.c uses scm_must_malloc to
39allocate a buffer that it returns, and scm_read_line passes this to
40scm_take_string. scm_take_string assumes that the memory has not been
41under GC control previously and calls scm_done_malloc to account for
42the fact that it now is. But scm_must_malloc has _already_ increased
43scm_mallocated by the proper amount. Thus, it is now doubly
44reflected.
45
46Since the current interface is unsymmetrical (scm_must_malloc
47registers, but scm_must_free doesn't de-register), I propose to change
48it as follows. Switching to this new interface will force us and
49everybody else to systematically review their code.
50
51 - the smob free routine does no longer return the number of bytes
52 that have been freed. For the transition period, free routines
53 are first encourged to return 0, then required, and then their
54 return type changes to void.
55
56 - scm_must_malloc, scm_must_free are deprecated.
57
58 - in their place, we have
59
28d9cc1d 60 Function: void *scm_malloc (size_t size);
2e203f2d
MV
61
62 Allocate SIZE bytes of memory. When not enough memory is
63 available, signal an error. This function runs the GC to free
64 up some memory when it deems it appropriate.
65
28d9cc1d
MV
66 The memory is allocated by the libc "malloc" function and can
67 be freed with "free". We do not introduce a `scm_free'
68 function to go with scm_malloc to make it easier to pass
69 memory back and forth between different modules.
2e203f2d
MV
70
71 [ Note: this function will not consider the memory block to be
72 under GC control. ]
73
2e203f2d
MV
74 Function: void *scm_realloc (void *mem, size_t newsize);
75
76 Change the size of the memory block at MEM to NEWSIZE. A new
77 pointer is returned. When NEWSIZE is 0 this is the same as
28d9cc1d
MV
78 calling scm_free on MEM and NULL is returned. When MEM is
79 NULL, this function behaves like scm_malloc and allocates a
80 new block of size SIZE.
81
82 When not enough memory is available, signal an error. This
83 function runs the GC to free up some memory when it deems it
84 appropriate.
2e203f2d
MV
85
86 Function: void scm_gc_register_collectable_memory
87 (void *mem, size_t size, const char *what);
88
89 Informs the GC that the memory at MEM of size SIZE can
28d9cc1d
MV
90 potentially be freed during a GC. That is, announce that MEM
91 is part of a GC controlled object and when the GC happens to
92 free that object, SIZE bytes will be freed along with it. The
93 GC will _not_ free the memory itself, it will just know that
94 so-and-so much bytes of memory are associated with GC
95 controlled objects and the memory system figures this into its
96 decisions when to run a GC.
2e203f2d
MV
97
98 MEM does not need to come from scm_malloc. You can only call
99 this function once for every memory block.
100
28d9cc1d
MV
101 The WHAT argument is used for statistical purposes. It should
102 describe the type of object that the memory will be used for
103 so that users can identify just what strange objects are
104 eating up their memory.
105
2e203f2d
MV
106 Function: void scm_gc_unregister_collectable_memory
107 (void *mem, size_t size);
108
109 Inform the GC that the memory at MEM of size SIZE is no longer
28d9cc1d
MV
110 associated with a GC controlled object. You must take care to
111 match up every call to scm_gc_register_collectable_memory with
112 a call to scm_gc_unregister_collectable_memory. If you don't
113 do this, the GC might have a wrong impression of what is going
114 on and run much less efficiently than it could.
2e203f2d
MV
115
116 Function: void *scm_gc_malloc (size_t size, const char *what);
28d9cc1d
MV
117 Function: void *scm_gc_realloc (void *mem, size_t size,
118 const char *what);
2e203f2d
MV
119
120 Like scm_malloc, but also call scm_gc_register_collectable_memory.
121
122 Function: void scm_gc_free (void *mem, size_t size, const char *what);
123
28d9cc1d 124 Like free, but also call scm_gc_unregister_collectable_memory.
2e203f2d
MV
125
126 Note that you need to explicitely pass the SIZE parameter.
127 This is done since it should normally be easy to provide this
128 parameter (for memory that is associated with GC controlled
129 objects) and this frees us from tracking this value in the GC
130 itself. (We don't do this out of lazyness but because it will
131 keep the memory management overhead very low.)
132
133The normal thing to use is scm_gc_malloc / scm_gc_free.
134
135
136Cell allocation and initialization
137----------------------------------
138
28d9cc1d
MV
139The following has been implemented in the unstable branch now.
140
2e203f2d
MV
141It can happen that the GC is invoked during the code that initializes
142a cell. The half initialized cell is seen by the GC, which would
143normally cause it to crash. To prevent this, the initialization code
144is careful to set the type tag of the cell last, so that the GC will
145either see a completely initialized cell, or a cell with type tag
146`free_cell'. However, some slot of that `free' cell might be the only
147place where a live object is referenced from (since the compiler might
148reuse the stack location or register that held it before it was
149stuffed into the cell). To protect such an object, the contents of
150the cell (except the first word) is marked conservatively.
151
152What happened to me was that scm_gc_mark hit upon a completely
153uninitialized cell, that was tagged a s a free cell, and still pointed
154to the rest of the freelist were it came from. (It was probably this code
155
156 :
157 SCM_NEWCELL (port); // port is a free cell
158 SCM_DEFER_INTS;
159 pt = scm_add_to_port_table (port); // this invokes the GC
160 :
161
162that caused it.)
163
164scm_gc_mark would conservatively mark the cdr of the free cell, which
165resulted in marking the whole free list. This caused a stack overflow
166because the marking didn't happen in a tail-calling manner. (Even if
167it doesn't crash, a lot of unnecessary work is done.)
168
169I propose to change the current practice so that no half initialized
170cell is ever seen by the GC. scm_gc_mark would abort on seeing a free
171cell, and scm_mark_locations (and scm_gc_mark_cell_conservatively if
172will survive) would not mark a free cell, even if the pointer points
173to a valid cell. scm_gc_sweep would continue to ignore free cells.
174
175To ensure that initialization can not be interrupted by a GC, we
176provide new functions/macros to allocate a cell that include
177initialization. For example
178
179 SCM scm_newcell_init (scm_bits_t car, scm_bits_t cdr)
180 {
181 SCM z;
182 if (SCM_NULLP (scm_freelist))
183 z = scm_gc_for_newcell (&scm_master_freelist,
184 &scm_freelist);
185 else
186 {
187 z = scm_freelist;
188 scm_freelist = SCM_FREE_CELL_CDR (scm_freelist);
189 }
190 SCM_SET_CELL_WORD_1 (z, cdr);
191 SCM_SET_CELL_WORD_0 (z, car);
192 scm_remember_upto_here (cdr);
193 return into;
194 }
195
196For performance, we might turn this into a macro, and find some
197specialized ways to make the compiler remember certain values (like
198some `asm' statement for GCC). For a non-threaded Guile, and a
199cooperatively threaded one, the scm_remember_upto_here call is not
200even needed since we know the the function can not be
201interrupted. (Signals can not interrupt the flow of control any
202longer).
203
204In the transition period, while SCM_NEWCELL is deprecated, we can make
205it always initialize the first slot with scm_tc16_allocated. Such
206cells are marked conservatively by the GC. SCM_NEWCELL can have
207abysmal performance while being deprecated.