Mercurial > hg > xemacs-beta
comparison src/gc.c @ 5238:2cc24c69446c
Document the new allocator and the new garbage collector in gc.c and mc-alloc.c.
author | Marcus Crestani <crestani@informatik.uni-tuebingen.de> |
---|---|
date | Mon, 05 Jul 2010 18:17:39 +0200 |
parents | 71ee43b8a74d |
children | 308d34e9f07d |
comparison
equal
deleted
inserted
replaced
5237:6466bc9ebf15 | 5238:2cc24c69446c |
---|---|
18 along with XEmacs; see the file COPYING. If not, write to | 18 along with XEmacs; see the file COPYING. If not, write to |
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
20 Boston, MA 02111-1307, USA. */ | 20 Boston, MA 02111-1307, USA. */ |
21 | 21 |
22 /* Synched up with: Not in FSF. */ | 22 /* Synched up with: Not in FSF. */ |
23 | |
24 /* | |
25 Garbage Collectors in XEmacs | |
26 | |
27 Currently, XEmacs comes with two garbage collectors: | |
28 | |
29 - The "old garbage collector": a simple mark and sweep collector, | |
30 its implementation is mainly spread out over gc.c and alloc.c. | |
31 It is used by the default configuration or if you configure | |
32 `--with-newgc=no'. | |
33 | |
34 - The "new garbage collector": an incremental mark and sweep collector, | |
35 its implementation is in gc.c. It is used if you configure | |
36 `--with-newgc'. It comes with a new allocator, see mc-alloc.c, and | |
37 with the KKCC mark algorith, see below. | |
38 | |
39 Additionally, the old garbage collectors comes with two mark algorithms: | |
40 | |
41 - The "recursive mark algorithm" marks live objects by recursively | |
42 calling mark_* functions on live objects. It is the default mark | |
43 algorithm of the old garbage collector. | |
44 | |
45 - The "KKCC mark algorithm" uses an explicit stack that to keep | |
46 track of the current progress of traversal and uses memory layout | |
47 descriptions (that are also used by the portable dumper) instead | |
48 of the mark_* functions. The old garbage collector uses it if | |
49 you configure `--with-kkcc'. It is the default and only mark | |
50 algorithm of the new garbage collector. | |
51 | |
52 | |
53 The New Incremental Garbage Collector | |
54 | |
55 An incremental garbage collector keeps garbage collection pause | |
56 times short by interleaving small amounts of collection work with | |
57 program execution, it does that by instrumenting write barrier | |
58 algorithms that essentially allow interrupting the mark phase. | |
59 | |
60 | |
61 Write Barrier | |
62 | |
63 A write barrier is the most important prerequisite for fancy | |
64 garbage collection techniques. We implement a "Virtual Dirty Bit | |
65 (short: vdb) Write Barrier" that makes uses of the operating | |
66 system's memory-protection mechanisms: The write barrier | |
67 write-protects memory pages containing heap objects. If the | |
68 mutator tries to modify these objects by writing into the | |
69 write-protected page, the operating system generates a fault. The | |
70 write barrier catches this fault, reads out the error-causing | |
71 address and can thus identify the updated object and page. | |
72 | |
73 Not all environments and operating systems provide the mechanism to | |
74 write-protect memory, catch resulting write faults, and read out | |
75 the faulting address. But luckily, most of today's operating | |
76 systems provide the features needed for the write-barrier | |
77 implementation. Currently, XEmacs includes write-barrier | |
78 implementations for the following platforms: | |
79 | |
80 - POSIX-compliant platforms like up-to-date UNIX, Linux, Solaris, | |
81 etc. use the system call `mprotect' for memory protection, | |
82 `sigaction' for signal handling and get the faulting address from | |
83 `struct siginfo'. See file vdb-posix.c. | |
84 | |
85 - Mach-based systems like Mac OS X use "Mach Exception Handlers". | |
86 See file vdb-mach.c. | |
87 | |
88 - Windows systems like native Windows and Cygwin use Microsoft's | |
89 so-called "Structured Exception Handling". See file vdb-win32.c. | |
90 | |
91 The configure script determines which write barrier implementation | |
92 to use for a system. If no write barrier implementation is working | |
93 on that system, a fall-back "fake" implementation is used: This | |
94 implementation simply turns of the incremental write barrier at | |
95 runtime and does not allow any incremental collection (see | |
96 vdb-fake.c). The garbage collector then acts like a traditional | |
97 mark-and-sweep garbage collector. Generally, the incremental | |
98 garbage collector can be turned of at runtime by the user or by | |
99 applications, see below. | |
100 | |
101 | |
102 Memory Protection and Object Layout | |
103 | |
104 Implementations of a memory-protection mechanism may restrict the | |
105 size and the alignment of the memory region to be on page-size | |
106 boundaries. All objects subject to be covered by the write barrier | |
107 have to be allocated on logical memory pages, so that they meet the | |
108 requirement to be write-protected. The new allocator mc-alloc is | |
109 aware of a system page size---it allocates all Lisp objects on | |
110 logical memory pages and is therefore defaulted to on when the new | |
111 garbage collector is enabled. | |
112 | |
113 Unfortunately, the Lisp object layout that works with the old | |
114 collector leads to holes in the write barrier: Not all data | |
115 structures containing pointers to Lisp objects are allocated on the | |
116 Lisp heap. Some Lisp objects do not carry all their information in | |
117 the object itself. External parts are kept in separately allocated | |
118 memory blocks that are not managed by the new Lisp allocator. | |
119 Examples for these objects are hash tables and dynamic arrays, two | |
120 objects that can dynamically grow and shrink. The separate memory | |
121 blocks are not guaranteed to reside on page boundaries, and thus | |
122 cannot be watched by the write barrier. | |
123 | |
124 Moreover, the separate parts can contain live pointers to other Lisp | |
125 objects. These pointers are not covered by the write barrier and | |
126 modifications by the client during garbage collection do escape. In | |
127 this case, the client changes the connectivity of the reachability | |
128 graph behind the collector's back, which eventually leads to | |
129 erroneous collection of live objects. To solve this problem, I | |
130 transformed the separately allocated parts to fully qualified Lisp | |
131 objects that are managed by the allocator and thus are covered by | |
132 the write barrier. This also removes a lot of special allocation | |
133 and removal code for the out-sourced parts. Generally, allocating | |
134 all data structures that contain pointers to Lisp objects on one | |
135 heap makes the whole memory layout more consistent. | |
136 | |
137 | |
138 Debugging | |
139 | |
140 The virtual-dirty-bit write barrier provokes signals on purpose, | |
141 namely SIGSEGV and SIGBUS. When debugging XEmacs with this write | |
142 barrier running, the debugger always breaks whenever a signal | |
143 occurs. This behavior is generally desired: A debugger has to break | |
144 on signals, to allow the user to examine the cause of the | |
145 signal---especially for illegal memory access, which is a common | |
146 programming error. But the debugger should not break for signals | |
147 caused by the write barrier. Therefore, most debuggers provide the | |
148 ability to turn of their fault handling for specific signals. The | |
149 configure script generates the debugger's settings .gdbinit and | |
150 .dbxrc, adding code to turn of signal handling for SIGSEGV and | |
151 SIGBUS, if the new garbage collector is used. | |
152 | |
153 But what happens if a bug in XEmacs causes an illegal memory access? | |
154 To maintain basic debugging abilities, we use another signal: First, | |
155 the write-barrier signal handler has to determine if the current | |
156 error situation is caused by the write-barrier memory protection or | |
157 not. Therefore, the signal handler checks if the faulting address | |
158 has been write-protected before. If it has not, the fault is caused | |
159 by a bug; the debugger has to break in this situation. To achieve | |
160 this, the signal handler raises SIGABRT to abort the program. Since | |
161 SIGABRT is not masked out by the debugger, XEmacs aborts and allows | |
162 the user to examine the problem. | |
163 | |
164 | |
165 Incremental Garbage Collection | |
166 | |
167 The new garbage collector is still a mark-and-sweep collector, but | |
168 now the mark phase no longer runs in one atomic action, it is | |
169 interleaved with program execution. The incremental garbage | |
170 collector needs an explicit mark stack to store the state of the | |
171 incremental traversal: the KKCC mark algorithm is a prerequisite and | |
172 is enabled by default when the new garbage collector is on. | |
173 | |
174 Garbage collection is invoked as before: After `gc-cons-threshold' | |
175 bytes have been allocated since the last garbage collection (or | |
176 after `gc-cons-percentage' percentage of the total amount of memory | |
177 used for Lisp data has been allocated since the last garbage | |
178 collection) a collection starts. After some initialization, the | |
179 marking begins. | |
180 | |
181 The variable `gc-incremental-traversal-threshold' contains how many | |
182 steps of incremental work have to be executed in one incremental | |
183 traversal cycle. After that many steps have been made, the mark | |
184 phase is interrupted and the client resumes. Now, the Lisp memory | |
185 is write-protected and the write barrier records modified objects. | |
186 Incremental traversal is resumed after | |
187 `gc-cons-incremental-threshold' bytes have been allocated since the | |
188 interruption of garbage collection. Then, the objects recorded by | |
189 the write-barrier have to be re-examined by the traversal, i.e. they | |
190 are re-pushed onto the mark stack and processed again. Once the | |
191 mark stack is empty, the traversal is done. | |
192 | |
193 A full incremental collection is slightly slower than a full garbage | |
194 collection before: There is an overhead for storing pointers into | |
195 objects when the write barrier is running, and an overhead for | |
196 repeated traversal of modified objects. However, the new | |
197 incremental garbage collector reduces client pause times to | |
198 one-third, so even when a garbage collection is running, XEmacs | |
199 stays reactive. | |
200 | |
201 | |
202 Tricolor Marking: White, Black, and Grey Mark Bits | |
203 | |
204 Garbage collection traverses the graph of reachable objects and | |
205 colors them. The objects subject to garbage collection are white at | |
206 the beginning. By the end of the collection, those that will be | |
207 retained are colored black. When there are no reachable objects left | |
208 to blacken, the traversal of live data structures is finished. In | |
209 traditional mark-and-sweep collectors, this black and white coloring | |
210 is sufficient. | |
211 | |
212 In an incremental collector, the intermediate state of the traversal | |
213 is im- portant because of ongoing mutator activity: the mutator | |
214 cannot be allowed to change things in such way that the collector | |
215 will fail to find all reachable objects. To understand and prevent | |
216 such interactions between the mutator and the collector, it is | |
217 useful to introduce a third color, grey. | |
218 | |
219 Grey objects have been reached by the traversal, but its descendants | |
220 may not have been. White objects are changed to grey when they are | |
221 reached by the traversal. Grey objects mark the current state of the | |
222 traversal: traversal pro- ceeds by processing the grey objects. The | |
223 KKCC mark stack holds all the currently grey-colored objects. | |
224 Processing a grey object means following its outgoing pointers, and | |
225 coloring it black afterwards. | |
226 | |
227 Intuitively, the traversal proceeds in a wavefront of grey objects | |
228 that separates the unreached objects, which are colored white, from | |
229 the already processed black objects. | |
230 | |
231 The allocator takes care of storing the mark bits: The mark bits are | |
232 kept in a tree like structure, for details see mc-alloc.c. | |
233 | |
234 | |
235 Internal States of the Incremental Garbage Collector | |
236 | |
237 To keep track of its current state, the collector holds it's current | |
238 phase in the global `gc_state' variable. A collector phase is one | |
239 of the following: | |
240 | |
241 NONE No incremental or full collection is currently running. | |
242 | |
243 INIT_GC The collector prepares for a new collection, e.g. sets some | |
244 global variables. | |
245 | |
246 PUSH_ROOT_SET The collector pushes the root set on the mark stack | |
247 to start the traversal of live objects. | |
248 | |
249 MARK The traversal of live objects colors the reachable objects | |
250 white, grey, or black, according to their lifeness. The mark | |
251 phase can be interrupted by the incremental collection algorithm: | |
252 Before the client (i.e. the non collector part of XEmacs) resumes, | |
253 the write barrier has to be installed so that the collector knows | |
254 what objects get modified during the collector's pause. | |
255 Installing a write barrier means protecting pages that only | |
256 contain black objects and recording write access to these objects. | |
257 Pages with white or grey objects do not need to be protected, | |
258 since these pages are due to marking anyways when the collector | |
259 resumes. Once the collector resumes, it has to re-scan all | |
260 objects that have been modified during the collector pause and | |
261 have been caught by the write barrier. The mark phase is done when | |
262 there are no more grey objects on the heap, i.e. the KKCC mark stack | |
263 is empty. | |
264 | |
265 REPUSH_ROOT_SET After the mark phase is done, the collector has to | |
266 traverse the root set pointers again, since modifications to the | |
267 objects in the root set can not all be covered by the write barrier | |
268 (e.g. root set objects that are on the call stack). Therefore, the | |
269 collector has to traverse the root set again without interruption. | |
270 | |
271 FINISH_MARK After the mark phase is finished, some objects with | |
272 special liveness semantics have to be treated separately, e.g. | |
273 ephemerons and the various flavors of weak objects. | |
274 | |
275 FINALIZE The collector registers all objects that have finalizers | |
276 for finalization. Finalizations happens asynchronously sometimes | |
277 after the collection has finished. | |
278 | |
279 SWEEP The allocator scans the entire heap and frees all white marked | |
280 objects. The freed memory is recycled and can be re-used for future | |
281 allocations. The sweep phase is carried out atomically. | |
282 | |
283 FINISH_GC The collector cleans up after the garbage collection by | |
284 resetting some global variables. | |
285 | |
286 | |
287 Lisp Interface | |
288 | |
289 The new garbage collector can be accessed directly from Emacs Lisp. | |
290 Basically, two functions invoke the garbage collector: | |
291 | |
292 (gc-full) starts a full garbage collection. If an incremental | |
293 garbage collection is already running, it is finished without | |
294 further interruption. This function guarantees that unused | |
295 objects have been freed when it returns. | |
296 | |
297 (gc-incremental) starts an incremental garbage collection. If an | |
298 incremental garbage collection is already running, the next cycle | |
299 of incremental traversal is started. The garbage collection is | |
300 finished if the traversal completes. Note that this function does | |
301 not necessarily free any memory. It only guarantees that the | |
302 traversal of the heap makes progress. | |
303 | |
304 The old garbage collector uses the function (garbage-collect) to | |
305 invoke a garbage collection. This function is still in use by some | |
306 applications that explicitly want to invoke a garbage collection. | |
307 Since these applications may expect that unused memory has really | |
308 been freed when (garbage-collect) returns, it maps to (gc-full). | |
309 | |
310 The new garbage collector is highly customizable during runtime; it | |
311 can even be switched back to the traditional mark-and-sweep garbage | |
312 collector: The variable allow-incremental-gc controls whether | |
313 garbage collections may be interrupted or if they have to be carried | |
314 out in one atomic action. Setting allow-incremental-gc to nil | |
315 prevents incremental garbage collection, and the garbage collector | |
316 then only does full collects, even if (gc-incremental) is called. | |
317 Non-nil allows incremental garbage collection. | |
318 | |
319 This way applications can freely decide what garbage collection | |
320 algorithm is best for the upcoming memory usage. How frequently a | |
321 garbage collection occurs and how much traversal work is done in one | |
322 incremental cycle can also be modified during runtime. See | |
323 | |
324 M-x customize RET alloc RET | |
325 | |
326 for an overview of all settings. | |
327 | |
328 | |
329 More Information | |
330 | |
331 More details can be found in | |
332 http://crestani.de/xemacs/pdf/thesis-newgc.pdf . | |
333 | |
334 */ | |
23 | 335 |
24 #include <config.h> | 336 #include <config.h> |
25 #include "lisp.h" | 337 #include "lisp.h" |
26 | 338 |
27 #include "backtrace.h" | 339 #include "backtrace.h" |
48 #include "sysdep.h" | 360 #include "sysdep.h" |
49 #include "window.h" | 361 #include "window.h" |
50 #include "vdb.h" | 362 #include "vdb.h" |
51 | 363 |
52 | 364 |
365 /* Number of bytes of consing since gc before a full gc should happen. */ | |
53 #define GC_CONS_THRESHOLD 2000000 | 366 #define GC_CONS_THRESHOLD 2000000 |
367 | |
368 /* Number of bytes of consing since gc before another cycle of the gc | |
369 should happen in incremental mode. */ | |
54 #define GC_CONS_INCREMENTAL_THRESHOLD 200000 | 370 #define GC_CONS_INCREMENTAL_THRESHOLD 200000 |
371 | |
372 /* Number of elements marked in one cycle of incremental GC. */ | |
55 #define GC_INCREMENTAL_TRAVERSAL_THRESHOLD 100000 | 373 #define GC_INCREMENTAL_TRAVERSAL_THRESHOLD 100000 |
56 | 374 |
57 /* Number of bytes of consing done since the last GC. */ | 375 /* Number of bytes of consing done since the last GC. */ |
58 EMACS_INT consing_since_gc; | 376 EMACS_INT consing_since_gc; |
59 | 377 |