layout | title |
---|---|
default |
Garbage Collection |
Translated by Sebastian Krause
Itâs all of a sudden but at the beginning of this chapter, weâll
learn about the memory space of an executing program. In this chapter
we deal with the lower level parts of a computer quite a bit, so without
preliminary knowledge itâll be hard to follow. And itâll be also necessary
for the following chapters. If we finish this, the rest will be a piece of cake.
The memory space of a general C program has the following parts:
- the text area
- a place for static and global variables
- the machine stack
- the heap
The text area is where the code lies. Obviously the second area holds static and global variables.
Function calls, along with their arguments and local variables are piled up in the machine stack.
The heap is allocated by `malloc()`.
Letâs talk a bit about number three, the machine stack.
Obviously, because itâs the machine-âstackâ it has the structure of a stack.
In other words new stuff is piled on top of it.
The new in a word fast one is piled up. There is a large a little more unit when logically seeing when the value is actually piled up in the machine stack because it piles up by a detailed unit of `int` 1 piece etc. It is called stack frame (stack frame).
One stack frame corresponds to one function call. Or in other words when there is a function call, one stack frame is added.
With the return
the stack frame descends by one. Really simplified the stack frame looks as shown below.
äžïŒå
端ïŒabove (top)
äžïŒæ«ç«¯ïŒbelow (bottom)
ã¹ã¿ãã¯ãã¬ãŒã stack frame
çŸåšå®è¡äžã®é¢æ°ãã¬ãŒã presently executing function frame
In this picture the top of the stack is depicted above,
but this it is not necessarily always the case that it goes
from low addresses to high addresses. For instance on the x86
machine the stack goes from high to low addresses.
By using `malloc()` itâs possible to get an abitrarily large memory
area of the heap. `alloca()` is the machine stack version of it.
But unlike `malloc()` itâs not necessary to free the memory allocated
with `alloca()`. Or one should say:
it is freed automatically with the return
of the function.
Thatâs why itâs not possible to have an allocated value as the return
value (?). Itâs the same as âYou must not return the pointer to
a local variable.â
ãããŸã§ã¯ãããé·ããå®è¡æã«å€ããããé
åãããŒã«ã«ã«å²ãåœãŠãããã
ãšããçšåºŠã®ããšã ã
However there exist environments where there is no native `alloca()`.
In this case there are still many who would like to use alloca()
,
they write versions of this function in C
.
ã ãäžã®äžã«ã¯ãã€ãã£ãã®`alloca()`ããªãç°å¢ãšããã®ããããããããå Ž
åã§ã`alloca()`ã¯äœ¿ããããšæã人ã¯å€ãã®ã§ãåãåããããé¢æ°ãCã§
æžããŠãã£ããããããã ãã®å Žåã¯ã解æŸããå¿
èŠããªãããšããç¹åŸŽã ã
ãå®è£
ãããŠããŠããã·ã³ã¹ã¿ãã¯äžã«ã¡ã¢ãªãå²ãåœãŠãŠããããšã¯éããª
ãããšèšãããæ®éã¯åããªãããããã§ãããªããããããã€ãã£ãã®
`alloca()`ãå®è£
ã§ãããšããããšã ããã ãIf you could do this a native
alloca()
could have been implemented in the first place.
How can one implement alloca()
in C? The simplest implementation is:
first allocate memory normally with malloc()
. Then remember the function
which called alloca()
and the assigned addresses in a global list.
After that whenever alloca()
is called check this list if the calling
function has already finished. If so set the allocated memory free with
free()
.
Dâalloca(8)ã®å¯Ÿå¿ãèšé² record the relation Dâ alloca(8)
Bâalloca(32)ã®å¯Ÿå¿ãèšé² record the relation Bâ alloca(32)
Dã§å²ãåœãŠãã¡ã¢ããè§£æŸ release the memory allocated in D
missing/alloca.c
in ruby
is an example of an emulated alloca()
.
From here on we can talk at last about the main subject of this chapter:
garbage collection.
Objects are normally on top of the memory. Naturally, if a lot of objects are created, a lot of memory is used. If memory
were infinite there would be no problem but at present there is always a limit to memory. Thatâs why the memory which is not
used anymore must be collected and recycled. More concretely the memory received through malloc()
must be returned with
free()
.
However, it is difficult to leave the management of malloc()
and free()
to the
program. Especially in object oriented programming if objects reference each other,
it is difficult to tell when to release memory.
ããã§ã¬ãŒããŒãžã³ã¬ã¯ã·ã§ã³ã ã
There garbage collection comes in.
With garbage collection the memory which has become unnecessary,
is gathered and automatically freed. With garbage collection
the worry, when to release some memory with @free(), has become
unnecessary. Depending on this the writing of a program becomes
considerably easier.
Besides, in some book there was written: Garbage collection cleans up
usable memory which has become fragmented. This is an action called
compaction. It makes the memory more compact.
ãšããã§ã以åäœãã®æ¬ã«ã䜿ããã¡ã¢ãªãããŸããã«ãªã£ãŠããã®ãæŽçã
ãã®ãGCããšæžããŠãã£ãã®ãèŠãããšããããããã¯ã
ã³ã³ãã¯ã·ã§ã³(compaction)ããšèšãäœæ¥ã ã
ã³ã³ãã¯ãã«ãªãããã³ã³ãã¯ã·ã§ã³ã§ããã
ã³ã³ãã¯ã·ã§ã³ããããšã¡ã¢ãªãã£ãã·ã¥ã«ããããããããªãã®ã§ã¹ããŒã
ã¢ããã«ãããªãã®å¹æãããã®ã ããããã¯GCã®äž»ç®çã§ã¯ãªããGCã®ç®ç
ã¯ãããŸã§ã¡ã¢ãªã®ååã§ãããå®éãã¡ã¢ãªã®ååã¯ããŠãã³ã³ãã¯ã·ã§ã³
ã¯ããªãGCãå€ãã`ruby`ã®GCãã³ã³ãã¯ã·ã§ã³ã¯ããªãã
ã§ã¯å
·äœçã«ã©ããªã·ã¹ãã ã§GCã䜿ããã®ã ãããã
CãC++ã§ã¯ã¢ããªã³ãšããŠäœ¿ãã
Boehm GC\footnote{Boehm GC `http://www.hpl.hp.com/personal/Hans_Boehm/gc`}ãš
ãããã®ãããã
ãŸãJavaãPerlãPythonãC#ãEiffelãªã©æè¿ã®èšèªã«ãšã£ãŠã¯GCã¯
æšæºè£
åã ããããŠãã¡ããRubyã«ãGCãããã
æ¬ç« ã§ã¯`ruby`ã®GCã®è©³çŽ°ãè¿œã£ãŠãããã察象ãšãªããã¡ã€ã«ã¯`gc.c`ã§ããã
Before we explain the GC algorithm, we should explain what garbage collection
is. In other words how can we tell that memory has become unnecessary?
To keep it more concrete letâs simplify the structure and assume that there
are only objects and links. This would look as shown in figure 3.
Object referred in global variables or objects on top of the language stack
are surely necessary. And objects referred to in instance variables of these
objects are also necessary. Again following links we reach more necessary
objects.
To put it more systematically, the necessary objects are all objects which
can be reached recursively via links starting at the surely necessary objects.
This is depicted in figure 4. Left of the line are all obviously necessary objects.
The objects which can be reached from them are colored black. These are the
necessary objects. The rest of the objects can be released.
ã«ãŒããªããžã§ã¯ããroot object
äžèŠãªãªããžã§ã¯ã unused object
ã«ãŒããªããžã§ã¯ãããåç
§ãããŠãããªããžã§ã¯ã an object referenced by the root object
To put it into jargon , the surely necessary objects
are the garbage collection root. It becomes the root
of the tree of object links.
GC was first implemented in Lisp. The GC in Lisp, the worldâs first
GC was of the type mark&sweep. Rubyâs GC is of the same type.
Garbage collection with Mark&sweep is pretty close to our definition of
ânecessary objectâ. First a mark is put on the root objects. From this starting
point all elements which are reached will also be marked. This is the mark phase.
At some point no new elements can be reached. The yielded elements are all checked
and the objects which do not have a marked are all released. This is the sweep.
There are two advantages.
- There does not need to be any (or almost any) concern for garbage collection
outside the implementation of GC. - Cycles can also be released. (Look up cycles in the section âReference Countâ below)
There are also two disadvantages.
- In order to make the sweep every object must be touched at least once.
- The load of the GC is concentrated at one point.
If you use the emacs editor there appears sometimes a Garbage collecting...
and it completely stops reacting. That is an example of the second disadvantage.
But this point can be alleviated by modifying the algorithm (incremental GC).
Stop and Copy is a variation of Mark and Sweep. First we prepare the object area in several
ways. We simplify by assuming there are two areas A
and B
. We mark both as active
.
Always when creating an object we mark it as active
.
The garbage collection starts as with mark&sweep at the root elemnts.
But instead of marking elements it moves them to another region (Fig.6).
When all the links have been followed the elements which remain in A
are all discarded. Next we make B
active.
Stop and Copy has two advantages:
- Compaction happens at the same time as collecting the memory
- Objects that reference each other move closer together, improving memory cache hits
The second point is both good and bad:
- The area needed for storing objects needs to be twice as big
- The position of the object changes
There does not seem to be an allaround positive thing.
Reference count differs a bit from the aforementioned, the check(??)
code is distributed in several places.
First each elements get an integer counter. When it is referenced via
variables or arrays the counter of the referenced object is increased.
When the reference ends the counter is decreased. When the counter
becomes zero the object is released. This is the reference counter method.
(Fig.7)
There are two advantages:
- The load of GC is distributed to the entire program.
- The object that became unnecessary is immediately freed.
And there are two disadvantages.
- Handling the counters tends to be forgotten.
- When doing it naively cycles are not released.
Letâs explain about the second point. A cycle is
a cycle of references as shown in figure 8.
If this is the case the counters will never vanish
and the objects will not be released.
By the way, latest Python(2.2) uses reference count GC and cycles can be freed.
However, it is not because of the reference count, but because it occasionally uses mark and sweep to check for them.
Rubyâs garbage collection is only concerned with ruby objects.
Objects must be created and managed by ruby. In other words
if the user allocates memory by himself ruby want take care of it.
For instance the following function will create a memory leak in ruby.
void not_ok() { malloc(1024); /* receive memory and discard it */ }
However, the following function does not cause the memory leak.
void this_is_ok() { rb_ary_new(); /* create a ruby array and discard it */ }
rb_ary_new()
uses Rubyâs proper interface to allocate memory.
Rubyâs garbage collection will take care of it.
As objects are really structures, object management is really
management of these structures. Of course there are also the non-pointer
objects like Fixnum Symbol nil true false
which are not of this form.
We will not deal with this distinction here.
The size of the structure varies for the different types, how can we
keep management simple? We declare a union type of all the structures of
embedded classes. When we deal with memory we will deal with this union type.
The declaration of this union type is as follows.
⌠`RVALUE`
211 typedef struct RVALUE {
212 union {
213 struct {
214 unsigned long flags; /* 0 if not used */
215 struct RVALUE *next;
216 } free;
217 struct RBasic basic;
218 struct RObject object;
219 struct RClass klass;
220 struct RFloat flonum;
221 struct RString string;
222 struct RArray array;
223 struct RRegexp regexp;
224 struct RHash hash;
225 struct RData data;
226 struct RStruct rstruct;
227 struct RBignum bignum;
228 struct RFile file;
229 struct RNode node;
230 struct RMatch match;
231 struct RVarmap varmap;
232 struct SCOPE scope;
233 } as;
234 } RVALUE;(gc.c)
The element of struct RVALUE
is only one struct
.
`struct RVALUE`ã¯èŠçŽ ãäžã€ã ãã®æ§é äœã ã`union`ãçŽæ¥äœ¿ããªãã®ã¯ããã
ã°ãå°æ¥ã®æ¡åŒµã®ãšãã«ç°¡åã«ã¡ã³ããå¢ãããããã«ããããã ããã§ããã
ãŸãã¯å
±çšäœã®æåã®èŠçŽ `free.flags`ã«æ³šç®ããããã³ã¡ã³ãã«ã¯ã䜿ãããŠ
ããªããšãã¯ãŒãããšæžããŠãããæ¬åœã ãããããŸã 䜿ã£ãŠãããªããžã§ã¯
ãã®`free.flags`ãå¶ç¶0ã«ãªãããšã¯ãªãã®ã ãããã
第2ç« ããªããžã§ã¯ããã§èŠãããã«ãå
šãŠã®ãªããžã§ã¯ãæ§é äœã¯
`struct RBasic`ãæåã®èŠçŽ ã«æã€ãã ããå
±çšäœã®ã©ã®èŠçŽ ããã¢ã¯ã»ã¹ããŠã
`objâas.free.flags`ã¯`objâas.basic.flags`ãšæžãã®ãšåãããšã ããããŠ
ãªããžã§ã¯ãã¯å¿
ããã©ã°ã«æ§é äœåãã©ã°(`T_STRING`ãªã©)ãæã¡ããã
ããã®ãã©ã°ã¯å
šãŠ0以å€ãªã®ã§ããçããŠããããªããžã§ã¯ãã®ãã©ã°ãå¶
ç¶0ã«ãªãããšã¯ãªããã€ãŸããã©ã°ã0ã«ããããšã§ãæ»ã«ããªããžã§ã¯ãã
è¡šãã®ã¯å¿
èŠååã ãšç¢ºãããããã
The memory for all the object structures has been brought together in global variable `heaps`. Hereafter, letâs call this an object heap.ã
⌠Object heap
239 #define HEAPS_INCREMENT 10
240 static RVALUE **heaps;
241 static int heaps_length = 0;
242 static int heaps_used = 0;
243
244 #define HEAP_MIN_SLOTS 10000
245 static int *heaps_limits;
246 static int heap_slots = HEAP_MIN_SLOTS;(gc.c)
heaps
is an array of arrays of struct RVALUE
. The contained arrays
are each a heap
. The elements of heap
are each a slot
.
(Fig.9)ã
The length of heaps
can be changed in heap_length
. The number of
the slots actually in use is heaps_used
. The length of each heap
is in the corresponding heaps_limits[index]
. In other words the
structure of the object heap is as depicted in figure 10.
This structure must necessarily be this way.
ãã®æ§é ã«ã¯å¿
ç¶æ§ããããäŸãã°å
šãŠã®æ§é äœãäžã€ã®é
åã«é
眮ãããš
ã¡ã¢ãªç©ºéã¯æãã³ã³ãã¯ãã«ãªãããã¢ãã¬ã¹ãå€ãã£ãŠããŸãæãããã
ã®ã§`realloc()`ã§ããªãã`VALUE`ã¯åãªããã€ã³ã¿ã ããã ã
ãšããJavaã®å®è£
ã ãš`VALUE`ã«çžåœãããã®ãã¢ãã¬ã¹ã§ã¯ãªããŠãªããžã§ã¯
ãã®ã€ã³ããã¯ã¹ã§ããã€ã³ã¿ããŒãã«ãçµç±ããŠåãæ±ãããããã«ãªã£ãŠ
ããããããªããžã§ã¯ãã移åããããšãã§ããããã ããã®å Žåã¯
ãªããžã§ã¯ãã¢ã¯ã»ã¹ã®ãã³ã«é
åã®ã€ã³ãã¯ã·ã³ã°ãå
¥ãã®ã§å€å°
ããã©ãŒãã³ã¹ã¯èœã¡ãã
äžæ¹`RVALUE`ãžã®ãã€ã³ã¿(ã€ãŸã`VALUE`)ã®äžæ¬¡å
é
åã«ããå Žåã¯ã©ãã ã
ãããããã¯äžèŠããŸãããããã ããGCã®ãšãã«å°ã£ãŠããŸãããšããã®ãã
ãããã詳ããæžããšããã`ruby`ã®GCã§ã¯ã`VALUE`(`RVALUE`ãžã®ãã€ã³ã¿)ã
ãããæŽæ°ãç¥ãå¿
èŠãããããã ãå
šãŠã®`RVALUE`ããŠãã§ãã©ãã©ã®ã¢ãã¬
ã¹ã«é
眮ãããŠãããšãå
šãŠã®`RVALUE`ã®ã¢ãã¬ã¹ãšããã€ã³ã¿ãããããªãã
æŽæ°å
šãŠãããããæ¯èŒããªããã°ãããªããããã§ã¯GCã®é床㯠O(n^2) 以
äžã®ãªãŒããŒã«ãªãã容èªã§ããªãã
以äžã®æ¡ä»¶ããããªããžã§ã¯ãããŒãã¯ããçšåºŠã¢ãã¬ã¹ã«ãŸãšãŸããããã
ãããäœçœ®ãšç·éã¯å¶éãããªããããªæ§é ã«ããã®ããããšããããã ã
䜿ãããŠããªã`RVALUE`ã¯`freelist`ããå§ãŸããªã³ã¯
ãªã¹ãã«äžæ¬ã«ã€ãªãããŠç®¡çãããã`RVALUE`ã®`as.free.next`ã¯ãã®ãã
ã«äœ¿ããªã³ã¯ã ã
⌠`freelist`
236 static RVALUE *freelist = 0;(gc.c)
ããŒã¿æ§é ãããã£ããšããã§ããŒããè¿œå ããé¢æ°`add_heap()`ãèªãã§ã¿ã
ãããã®é¢æ°ã¯ããããšæ¬ç以å€ã®èšè¿°ãããããã®ã§ããšã©ãŒåŠçããã£ã¹
ããçããŠç°¡åã«ãããã®ãèŠããã
⌠`add_heap()`(ç°¡çŽç)
static void
add_heap()
{
RVALUE *p, *pend; /* å¿ èŠãªãheapsãã®ã°ã */ if (heaps_used == heaps_length) { heaps_length += HEAPS_INCREMENT; heaps = realloc(heaps, heaps_length * sizeof(RVALUE*)); heaps_limits = realloc(heaps_limits, heaps_length * sizeof(int)); } /* heapãäžã€å¢ãã */ p = heaps[heaps_used] = malloc(sizeof(RVALUE) * heap_slots); heaps_limits[heaps_used] = heap_slots; pend = p + heap_slots; if (lomem == 0 || lomem > p) lomem = p; if (himem < pend) himem = pend; heaps_used++; heap_slots *= 1.8; /* å²ãåœãŠãRVALUEãfreelistã«ã€ãªã */ while (p < pend) { pâas.free.flags = 0; pâas.free.next = freelist; freelist = p; p++; }}
以äžã®ç¹ã確èªããŠãããŠã»ããã
- `heap`ã®é·ãã¯`heap_slots`
- ãã®`heap_slots`ã¯`heap`ãäžã€å¢ããããšã«1.8åã«ãªã£ãŠãã
- `heaps[i]`ã®é·ã(ããŒãçææã®`heap_slots`ã®å€)ã¯`heaps_limits[i]`ã«æ ŒçŽãããŠãã
ãŸã`lomem`ãš`himem`ãå€æŽããŠããã®ããã®é¢æ°ã ããªã®ã§ããã®é¢æ°ã ããã
ä»çµã¿ãç解ã§ããããã®å€æ°ã«ã¯ãªããžã§ã¯ãããŒãã®æäžäœã¢ãã¬ã¹ãš
æäžäœã¢ãã¬ã¹ãå
¥ã£ãŠããã®ã§ããããã®å€ã¯ããšã§ã`VALUE`ã£ãœããæŽæ°ã
å€æãããšãã«äœ¿ãã
以äžã®ç¹ãç·åããŠèããã°ãªããžã§ã¯ããçæããæ¹æ³ã¯ããã«ãããã
`freelist`ã«ã€ãªãããŠãã`RVALUE`ãããã°ããã䜿ãããªããã°GCãããã
ããŒããå¢ããã°ããããªããžã§ã¯ãçæãè¡ãé¢æ°`rb_newobj()`ãèªãã§
確ãããŠã¿ããã
⌠`rb_newobj()`
297 VALUE
298 rb_newobj()
299 {
300 VALUE obj;
301
302 if (!freelist) rb_gc();
303
304 obj = (VALUE)freelist;
305 freelist = freelistâas.free.next;
306 MEMZEROobj, RVALUE, 1);
307 return obj;
308 }(gc.c)
`freelist`ã0ãã€ãŸãäœãã®æ§é äœããªããªãGCãèµ·åããŠé åãäœãã
ããäžã€ããªããžã§ã¯ããååã§ããªããŠãã`rb_gc()`ã®äžã§æ°ãã
é åãå²ãåœãŠãŠãããã®ã§åé¡ãªãããããŠ`freelist`ããæ§é äœã
äžã€åãåºãã`MEMZERO()`ã§0ãå
å¡«ããããè¿ãããšãªãã
説æãããšããã`ruby`ã®GCã¯ããŒã¯&ã¹ã€ãŒãã§ãããããŒã¯ãšã¯å
·äœçã«ã¯
`FL_MARK`ãã©ã°ãã»ããããããšã ã䜿ãããŠãã`VALUE`ãæ¢ããŠã¯
`FL_MARK`ãã»ããããããã§å
šéšèª¿ã¹ããšæã£ãããªããžã§ã¯ãããŒããèŠãŠã
`FL_MARK`ãã»ãããããŠããªããªããžã§ã¯ãã解æŸããã°ããã
`rb_gc_mark()`ã¯ãªããžã§ã¯ããååž°çã«ããŒã¯ããé¢æ°ã§ããã
⌠`rb_gc_mark()`
573 void
574 rb_gc_mark(ptr)
575 VALUE ptr;
576 {
577 int ret;
578 register RVALUE obj = RANY;
579
580 if (rb_special_const_p(ptr)) return; / special const not marked /
581 if (objâas.basic.flags == 0) return; / free cell /
582 if (objâas.basic.flags & FL_MARK) return; / already marked */
583
584 objâas.basic.flags |= FL_MARK;
585
586 CHECK_STACK(ret);
587 if (ret) {
588 if (!mark_stack_overflow) {
589 if (mark_stack_ptr â mark_stack < MARK_STACK_MAX) {
590 *mark_stack_ptr = ptr;
591 mark_stack_ptr++;
592 }
593 else {
594 mark_stack_overflow = 1;
595 }
596 }
597 }
598 else {
599 rb_gc_mark_children(ptr);
600 }
601 }(gc.c)
The definition of RANY()
is as follows. It is not particularly important.
⌠`RANY ((RVALUE*)(o))
(gc.c)
æåã«ãã€ã³ã¿ã§ãªããã®ãæ¢ã«è§£æŸãããªããžã§ã¯ãã®ãã§ãã¯ã
ããŒã¯ããããªããžã§ã¯ãã®ååž°ãã§ãã¯ãããã
obj->as.basic.flags |= FL_MARK;
ã§`obj`(ã€ãŸãé¢æ°ã®åŒæ°`ptr`)ãããŒã¯ãããã
ããããã次ã¯`obj`ããåºãŠããåç
§ã蟿ã£ãŠããŒã¯ããçªã§ããã
`rb_gc_mark_children()`ãããã ã
ãã®ä»ã®ã`CHECK_STACK()`ããå§ãŸã£ãŠãããããšæžããŠããã®ã¯ãã·ã³ã¹ã¿ã
ã¯æº¢ããé²ãããã®ä»æãã§ããã`rb_gc_mark()`ã¯ååž°åŒã³åºãã䜿ã£ãŠãªã
ãžã§ã¯ããããŒã¯ããããã倧ããªãªããžã§ã¯ãã¯ã©ã¹ã¿ããããšãã·ã³ã¹ã¿ã
ã¯ã®é·ãã足ããªããªãããšããããããã§ã¹ã¿ãã¯ã溢ãããã ã£ããååž°
ãäžæ¢ããŠãªããžã§ã¯ããã°ããŒãã«ãªãªã¹ãã«ç©ãã§ãããããšããããäž
床ããŒã¯ããªããããã«ããŠããã®ã ã
ãã®ã³ãŒãã¯æ¬çã§ã¯ãªãã®ã§çç¥ããã
ããŠã`rb_gc_mark_children()`ã ãã
å
éšã®åãã²ããã䞊ã¹ãŠå°éã«ããŒã¯ããŠããã ããªã®ã§é·ãããã«
é¢çœããªããããã§ã¯åçŽãªåæéšåã¯çç¥ããŠèŒããã
⌠`rb_gc_mark_children()`
603 void
604 rb_gc_mark_children(ptr)
605 VALUE ptr;
606 {
607 register RVALUE obj = RANY;
608
609 if (FL_TEST(obj, FL_EXIVAR)) {
610 rb_mark_generic_ivar((VALUE)obj);
611 }
612
613 switch (objâas.basic.flags & T_MASK) {
614 case T_NIL:
615 case T_FIXNUM:
616 rb_bug(ârb_gc_mark() called for broken objectâ);
617 break;
618
619 case T_NODE:
620 mark_source_filename(objâas.node.nd_file);
621 switch (nd_type(obj)) {
622 case NODE_IF: / 1,2,3 /
623 case NODE_FOR:
624 case NODE_ITER:
/ âŠâŠâŠâŠçç¥âŠâŠâŠâŠ /
749 }
750 return; / basic.klassã¯ããŒã¯ããªããŠãã /
751 }
752
753 rb_gc_mark(objâas.basic.klass);
754 switch (objâas.basic.flags & T_MASK) {
755 case T_ICLASS:
756 case T_CLASS:
757 case T_MODULE:
758 rb_gc_mark(objâas.klass.super);
759 rb_mark_tbl(objâas.klass.m_tbl);
760 rb_mark_tbl(objâas.klass.iv_tbl);
761 break;
762
763 case T_ARRAY:
764 if (FL_TEST(obj, ELTS_SHARED)) {
765 rb_gc_mark(objâas.array.aux.shared);
766 }
767 else {
768 long i, len = objâas.array.len;
769 VALUE *ptr = objâas.array.ptr;
770
771 for (i=0; i < len; i++) {
772 rb_gc_mark(ptr++);
773 }
774 }
775 break; /* âŠâŠâŠâŠçç¥âŠâŠâŠâŠ */ 837 default: 838 rb_bug(ârb_gc_mark(): unknown data type 0x%x(0x%x) %sâ, 839 objâas.basic.flags & T_MASK, obj, 840 is_pointer_to_heap(obj) ? âcorrupted objectâ : ânon objectâ); 841 } 842 }(gc.c)
`rb_gc_mark()`ãååž°åŒã³åºãããŠãããªããšããããšã ã確èªããŠãããã°
ããã§ãããçç¥ããéšåã«ã¯`NODE`ãš`T_xxxx`ãããããåæãããŠããã
`NODE`ã®ããšã¯ç¬¬äºéšã§çŽ¹ä»ããã
ãããš`T_DATA`(æ¡åŒµã©ã€ãã©ãªã«äœ¿ãæ§é äœ)ã®ããŒã¯ã®éšåã ãã¯ç¢ºèªãã
ãããšãããã®ã§èŠãŠãããããã®ã³ãŒãã¯äºã€ãã®`switch`æããæç²ããã
⌠`rb_gc_mark_children()`-`T_DATA`
789 case T_DATA:
790 if (objâas.data.dmark) (*objâas.data.dmark)(DATA_PTR(obj));
791 break;(gc.c)
ããã¯`rb_gc_mark()`ããã®é¡äŒŒã®é¢æ°ã§ã¯ãªãããŠãŒã¶ããããã£ãé¢æ°
`dmark`ã䜿ã£ãŠããããã®äžã§ã¯ãã¡ãã`rb_gc_mark()`ãªããªããªãã䜿
ãã ãããã䜿ããªãããšããããããäŸãã°æ¥µç«¯ãªå Žåã§èšããšããŠãŒã¶
å®çŸ©ã®ãªããžã§ã¯ãã«`VALUE`ãå
¥ã£ãŠããªããªãããŒã¯ããå¿
èŠã¯ãªãã ããã
ãããŸã§ã§ãªããžã§ã¯ãåäœã®è©±ã¯æžãã ã®ã§ãããããã¯å
šäœãçµ±èœããé¢æ°
`rb_gc()`ãèŠãŠããããšã«ãããããã§ããŒã¯ããŠããã®ããå¿
èŠã ãšããããšã
æããã«åãã£ãŠãããªããžã§ã¯ããã€ãŸããGCã®ã«ãŒããã ã
⌠`rb_gc()`
1110 void
1111 rb_gc()
1112 {
1113 struct gc_list list;
1114 struct FRAME * volatile frame; / gcc 2.7.2.3 -O2 bug?? */
1115 jmp_buf save_regs_gc_mark;
1116 SET_STACK_END;
1117
1118 if (dont_gc || during_gc) {
1119 if (!freelist) {
1120 add_heap();
1121 }
1122 return;
1123 } /* âŠâŠå šãŠã®ã«ãŒããããŒã¯ããâŠâŠ */1183 gc_sweep();
1184 }(gc.c)
ããŒã¯ãã¹ãã«ãŒãã¯ãã®åŸã§é çªã«èŠããŠããããäžç¹ã ã觊ããŠãããã
`ruby`ã§ã¯CPUã®ã¬ãžã¹ã¿ããã·ã³ã¹ã¿ãã¯ãã«ãŒããšããã
ããã¯ã€ãŸãCã®ããŒã«ã«å€æ°ãåŒæ°ãåæã«ããŒã¯ããããšããããšã ã
äŸãã°
static int f(void) { VALUE arr = rb_ary_new(); /* âŠâŠããããããâŠâŠ */ }
ãšããããã«ããã å€æ°ã«å
¥ããŠããã ãã§ãã®ãªããžã§ã¯ãã¯ä¿è·ãããã®
ã ãããã¯`ruby`ã®GCã®éåžžã«å€§ããªç¹åŸŽã§ããããã®æ©èœããããããã
`ruby`ã®æ¡åŒµã©ã€ãã©ãªã¯ç°æ§ã«æžãæããªã£ãŠããã®ã ã
ãã ããã¡ããã¹ã¿ãã¯ã«çœ®ãããŠããã®ã¯`VALUE`ã°ããã§ã¯ãªããäœã®é¢ä¿ã
ãªãå€ãããããååšããããã®ããããã©ããã£ãŠè§£æ±ºããŠããã®ããGCã®
å®è£
ãèŠãŠãããšãã®éµã ã
æåã¯ã€ã³ã¿ããªã¿ã䜿ã£ãŠãã(`ruby`ã®)ã¹ã¿ãã¯ãã¬ãŒã ã
ããŒã¯ããã第äžéšãŸã§è¡ãã°ãããäœè
ãã¯ãããã®ã§ä»ã¯ããŸã
æ·±ãèããªããŠãããã
⌠Marking the Ruby Stack
1130 /* mark frame stack */
1131 for (frame = ruby_frame; frame; frame = frameâprev) {
1132 rb_gc_mark_frame(frame);
1133 if (frameâtmp) {
1134 struct FRAME *tmp = frameâtmp;
1135 while (tmp) {
1136 rb_gc_mark_frame(tmp);
1137 tmp = tmpâprev;
1138 }
1139 }
1140 }
1141 rb_gc_mark((VALUE)ruby_class);
1142 rb_gc_mark((VALUE)ruby_scope);
1143 rb_gc_mark((VALUE)ruby_dyna_vars);(gc.c)
The frame, the class scope, the local variable scope, and the block local variable at that time are maintained respectively by the variable to which `ruby_frame ruby_class ruby_scope ruby_dyna_vars` points at the head of the stack of the evaluation machine respectively.
次ã«CPUã®ã¬ãžã¹ã¿ãããŒã¯ããã
⌠marking the registers
1148 FLUSH_REGISTER_WINDOWS;
1149 /* ããã§å šãŠã®ã¬ãžã¹ã¿ãjmp_bufã«ä¿åãããªããã°ãªããªã /
1150 setjmp(save_regs_gc_mark);
1151 mark_locations_array((VALUE)save_regs_gc_mark,
sizeof(save_regs_gc_mark) / sizeof(VALUE *));(gc.c)
`FLUSH_REGISTER_WINDOWS` is special. We will come to it later.
`setjmp()`ã¯æ¬åœã¯é éãžã£ã³ãã®ããã®é¢æ°ãªã®ã ãã©ã
ãã®å¯äœçšãšããŠåŒæ°(`jmp_buf`åã®å€æ°)ã«ã¬ãžã¹ã¿ã®å
容ã
ä¿åããããã«ãªã£ãŠããã
ãããå©çšããŠã¬ãžã¹ã¿ã®äžèº«ãããŒã¯ããããšããããã ã
ãã®ãããã¯ããªãè£æã£ãœãã
ãã ãdjgppãšHuman68kã ãã¯ç¹å¥æ±ããããŠããã
djgppãšããã®ã¯DOSçšã®`gcc`ç°å¢ã
Human68kã¯ã·ã£ãŒãã®X680x0ã·ãªãŒãºã®OSã ã
ãã®äºã€ã®ç°å¢ã§ã¯éåžžã®`setjmp()`ã§ã¯å
šãŠã®ã¬ãžã¹ã¿ãæžãããŸããªãã
ãã§ã`setjmp()`ã以äžã®ããã«ã€ã³ã©ã€ã³ã¢ã»ã³ãã©ã§åå®çŸ©ããŠæ瀺çã«ã¬ãžã¹ã¿ãæžãåºã
ãŠããã
⌠ãªãªãžãã«ç`setjmp`
1072 #ifdef GNUC
1073 #if defined(human68k) || defined(DJGPP)
1074 #if defined(human68k)
1075 typedef unsigned long rb_jmp_buf8;
1076 asm (â.even\n\ 2ãã€ãã¢ã©ã€ã³ã¡ã³ã
1077 rb_setjmp:\n\ é¢æ°rbsetjmp()ã®ã©ãã«
1078 move.l 4(sp),a0\n\ 第äžåŒæ°ãã¬ãžã¹ã¿a0ã«ããŒã
1079 movem.l d3-d7/a3-a5,(a0)\n\ a0ã®æãå ã«ã¬ãžã¹ã¿ãã³ããŒ
1080 moveq.l #0,d0\n\ d0ã«0ãã»ãã(è¿ãå€)
1081 rtsâ); return
1082 #ifdef setjmp
1083 #undef setjmp
1084 #endif
1085 #else
1086 #if defined(DJGPP)
1087 typedef unsigned long rb_jmp_buf6;
1088 asm (â.align 4\n\ 4ãã€ãã¢ã©ã€ã³ã¡ã³ããæ瀺
1089 rb_setjmp:\n\ é¢æ°rbsetjmp()ã®ã©ãã«
1090 pushl %ebp\n\ ebpãã¹ã¿ãã¯ã«ããã·ã¥
1091 movl %esp,%ebp\n\ ã¹ã¿ãã¯ãã€ã³ã¿ãebpã«ã»ãã
1092 movl 8(%ebp),%ebp\n\ 第äžåŒæ°ãæŸãebpã«ã»ãã
1093 movl %eax,(%ebp)\n\ 以äžãåã¬ãžã¹ã¿ã
1094 movl %ebx,4(%ebp)\n\ ebpã®æãå ã«ã¹ãã¢
1095 movl %ecx,8(%ebp)\n\
1096 movl %edx,12(%ebp)\n\
1097 movl %esi,16(%ebp)\n\
1098 movl %edi,20(%ebp)\n\
1099 popl %ebp\n\ ebpãã¹ã¿ãã¯ãã埩垰
1100 xorl %eax,%eax\n\ eaxã«0ãã»ãã(è¿ãå€)
1101 retâ); return
1102 #endif
1103 #endif
1104 int rb_setjmp (rb_jmp_buf);
1105 #define jmp_buf rb_jmp_buf
1106 #define setjmp rb_setjmp
1107 #endif /* human68k or DJGPP /
1108 #endif / GNUC */(gc.c)
ã¢ã©ã€ã³ã¡ã³ã(alignment)ãšããã®ã¯ã¡ã¢ãªã«å€æ°ã眮ããšãã®
å¶çŽã®ããšã ã
äŸãã°32ããããã·ã³ã§ã¯æ®é`int`ã¯32ãããã ããã¡ã¢ãªã®ã©
ãããã§ã32ãããåãåºããããã§ã¯å¿
ããããªããç¹ã«RISCãã·ã³ã ãšå¶
çŽã匷ããã4ã®åæ°ãã€ãããããšããå¶æ°ãã€ãããããšãããµãã«æ±ºã
ãããŠãããããããå¶çŽãããã»ããã¡ã¢ãªã¢ã¯ã»ã¹ãŠããããåçŽåã§ã
ã(ãã®çµæé«éåã§ãã)ããã ãã4ã®åæ°ãã€ãããããšããå¶çŽã
ãããªãã4ãã€ãã¢ã©ã€ã³ã¡ã³ãããšåŒã¶ã
ãŸãdjgppãHuman68kã®`cc`ã§ã¯ã³ã³ãã€ã©ãé¢æ°åã®å
é ã«ã¢ã³ããŒã©ã€ã³ã
ä»ããèŠçŽãããããã ãã ããã¢ã»ã³ãã©ã§Cã®é¢æ°ãæžããšãã¯èªåã§å
é ã«ã¢ã³ããŒã©ã€ã³(`_`)ãä»ããªããã°ãªããªãããã®ã¿ã€ãã®èŠçŽã¯ã©ã€
ãã©ãªé¢æ°ãšååãéè€ããªãããã«ããããã®å·¥å€«ã ãUNIXã§ãå°ãåãŸã§ã¯
ã¢ã³ããŒã©ã€ã³ãä»ããŠããããã ãä»ã¯ã»ãŒãªããªã£ãŠããã
ããŠãããŸã§ã§ã¬ãžã¹ã¿ã®äžèº«ã`jmp_buf`ã«æžãã ããã®ã§ã
次ã®ã³ãŒãã§ããŒã¯ããã
⌠ã¬ãžã¹ã¿ã®ããŒã¯(åæ²)
1151 mark_locations_array((VALUE*)save_regs_gc_mark,
sizeof(save_regs_gc_mark) / sizeof(VALUE *));(gc.c)
`mark_locations_array()`ãšããã®ãåããŠåºãŠããã
ããã¯å¥é
ç®ãšããŠèŠãŠãããã
⌠`mark_locations_array()`
500 static void
501 mark_locations_array(x, n)
502 register VALUE x;
503 register long n;
504 {
505 while (nâ) {
506 if (is_pointer_to_heap((void *)x)) {
507 rb_gc_mark(*x);
508 }
509 x++;
510 }
511 }(gc.c)
ãã®é¢æ°ã¯é
åããŸãšããŠããŒã¯ããããã®é¢æ°ãªã®ã ãããããŸã§ã®ããŒã¯
é¢æ°ãšã¯å°ãéãããããŸã§ã¯ç¢ºå®ã«`VALUE`ããã(ãªããžã§ã¯ããæããã€
ã³ã¿ã )ãšããã£ãŠããå ŽæãããŒã¯ããŠããããããä»åºŠããŒã¯ããããšã
ãŠããã®ã¯ã¬ãžã¹ã¿é åã§ãããã«ã¯`VALUE`以å€ã®ãã®ãããããšãååèã
ããããããã§ããŸããã®æ°å€ã`VALUE`ã§ããã(ãã€ã³ã¿ã§ããã)ã©ãã
調ã¹ãŠã¿ãŠããããããèŠãããªãã°å
šãŠãã€ã³ã¿ãšããŠæ±ãããšã«ããã
ãã®ãããªææ³ããä¿å®çGC(conservative GC)ããšåŒã¶ã
ããšããããå®å
šåŽã«åãããšãããšãããä¿å®çã ãšããããšãããã
ã§ã¯æ¬¡ã¯ãã®ã`VALUE`ã£ãœããã©ãããã調ã¹ãé¢æ°
`is_pointer_to_heap()`ãèŠããã
⌠`is_pointer_to_heap()`
480 static inline int
481 is_pointer_to_heap(ptr)
482 void ptr;
483 {
484 register RVALUE *p = RANY;
485 register RVALUE *heap_org;
486 register long i;
487
488 if (p < lomem || p > himem) return Qfalse;
489
490 / pããã€ã³ã¿ã§ããå¯èœæ§ãããã調ã¹ã /
491 for (i=0; i < heaps_used; i++) {
492 heap_org = heaps[i];
493 if (heap_org <= p && p < heap_org + heaps_limits[i] &&
494 ((((char)p)-((char*)heap_org))%sizeof(RVALUE)) == 0)
495 return Qtrue;
496 }
497 return Qfalse;
498 }(gc.c)
ç°¡åã«èª¬æãããšæ¬¡ã®ããã«ãªãã
- `RVALUE`ãããã¢ãã¬ã¹ã®æäžç«¯ãšæäžç«¯ã®éã«ããã調ã¹ã
- åããŒãã®ç¯å²å ã«ãããã©ãã調ã¹ã
- ãã®æ°å€ã`RVALUE`ã®å é ãæããŠãããã©ãã確ããã
ãã®ãããªä»çµã¿ãªã®ã§ãééã£ãŠæ¬åœã¯`VALUE`ã§ãªãå€ã`VALUE`ãš
æ±ã£ãŠããŸãããšãåœç¶ããããããå°ãªããšã䜿ã£ãŠãã
`VALUE`ãèŠä»ããããªãããšã¯ãªãã
ãããããã ãã®ãã¹ããããŠããã°æå³çã§ãªã
éããããã`VALUE`ã§ãªãå€ãæŸãããšã¯ãªããšæãããã®ã§ãGCã§
åŸãããå©ç¹ãèããã°ååã«åŠ¥åã§ããããšããããã ã
æåŸã«åŸåãã«ããŠããã`FLUSH_REGISTER_WINDOWS()`ã«ã€ããŠã
ã¬ãžã¹ã¿ãŠã£ã³ããŠ(register windows)ãšã¯ãã·ã³ã¹ã¿ãã¯ã®äžéšãCPUã®
äžã«çœ®ããŠããããšãã§ããæ©æ§ã§ãããããããã«çšéãçµã£ããã£ãã·ã¥
ã ãæè¿ã¯Sparcã¢ãŒããã¯ãã£ã«ããååšããªããã¬ãžã¹ã¿ãŠã£ã³ããŠã«ã
`VALUE`ãå
¥ã£ãŠããå¯èœæ§ãããã®ã§ããããåãã£ãŠã¡ã¢ãªã«èœãšããŠãã
å¿
èŠãããã
ãã¯ãã®äžèº«ã¯ãããªæãã ã
⌠`FLUSH_REGISTER_WINDOWS`
125 #if defined(sparc) || defined(sparc)
126 # if defined(linux) || defined(linux)
127 #define FLUSH_REGISTER_WINDOWS asm(âta 0Ã83â)
128 # else /* Solaris, not sparc linux /
129 #define FLUSH_REGISTER_WINDOWS asm(âta 0Ã03â)
130 # endif
131 #else / Not a sparc */
132 #define FLUSH_REGISTER_WINDOWS
133 #endif(defines.h)
`asm(âŠ)`ã¯åã蟌ã¿
ã¢ã»ã³ãã©ã ããã ãã¢ã»ã³ãã©ãšã¯èšã£ãŠããã®`ta`ãšããåœä»€ã¯
ç¹æš©åœä»€ã®
ã³ãŒã«ãã€ãŸãCPUã§ãªãOSã®åŒã³åºãã§ãããã ããããOSããšã«åœä»€ã
éãã®ã ããªããã³ã¡ã³ãã«ã¯LinuxãšSolarisããæžããŠããªããå®éã«ã¯
FreeBSDãNetBSDãSparcã§åãã®ã§ãã®ã³ã¡ã³ãã¯ééãã§ããã
ãããšãSparcã§ãªãå Žåã¯ãããããã©ãã·ã¥ããå¿
èŠããªãã®ã§ã
`FLUSH_REGISTER_WINDOWS`ãç¡ãšå®çŸ©ããŠããããã®ãããªã
ãã¯ããç¡ã«éãææ³ã¯ãããã°åºåãªã©ã«ã䜿ããè¶
æåææ³ã ã
ã§ã¯ãŸã`rb_gc()`ã®ç¶ãã«æ»ãããä»åºŠã¯ãã·ã³ã¹ã¿ãã¯ã«çœ®ããã
`VALUE`ãããŒã¯ããã
⌠ãã·ã³ã¹ã¿ãã¯ã®ããŒã¯
1152 rb_gc_mark_locations(rb_gc_stack_start, (VALUE*)STACK_END);
1153 #if defined(human68k)
1154 rb_gc_mark_locations((VALUE*)((char*)rb_gc_stack_start + 2),
1155 (VALUE*)((char*)STACK_END + 2));
1156 #endif(gc.c)
`rb_gc_stack_start`ãã¹ã¿ãã¯ã®éå§ã¢ãã¬ã¹(ã¹ã¿ãã¯ã®æ«å°Ÿ)ã§
`STACK_END`ãçµäºã¢ãã¬ã¹(å
端)ãããã
ãããŠ`rb_gc_mark_locations()`ãå®éã«ã¹ã¿ãã¯é åãããŒã¯ããã
`rb_gc_mark_locations()`ãäºåããã®ã¯ã¹ã¿ãã¯ã4ãã€ãã¢ã©ã€ã³ã¡ã³ãã§
ãªãã¢ãŒããã¯ãã£ãžã®å¯Ÿçã§ããã`rb_gc_mark_locations()`ã¯
`sizeof(VALUE)`åäœã§ããŒã¯ãè©Šãã®ã§ã2ãã€ãã¢ã©ã€ã³ã¡ã³ãã®ç°å¢ã ãšã
ãŸãããŒã¯ã§ããªãããšããããããã§2ãã€ããºã©ããŠããäžåºŠããŒã¯ãã
ããã ã
ã§ã¯`rb_gc_stack_start`ã`STACK_END`ã`rb_gc_mark_locations()`ã®
äžã€ãé çªã«èŠãŠãããã
æåã¯`rb_gc_stack_start`ã ããã®å€æ°ã¯`Init_stack()`äžã§ã ãã»ããã
ããã`Init_`ãšããååããæ³åãã€ããããããªããããã®é¢æ°ã¯`ruby`ã€ã³
ã¿ããªã¿ã®åæåã®æç¹ã§åŒã°ããã
⌠`Init_stack()`
1193 void
1194 Init_stack(addr)
1195 VALUE addr;
1196 {
1197 #if defined(human68k)
1198 extern void *_SEND;
1199 rb_gc_stack_start = SEND;
1200 #else
1201 VALUE start;
1202
1203 if (!addr) addr = &start;
1204 rb_gc_stack_start = addr;
1205 #endif
1206 #ifdef HAVE_GETRLIMIT
1207 {
1208 struct rlimit rlim;
1209
1210 if (getrlimit(RLIMIT_STACK, &rlim) == 0) {
1211 double space = (double)rlim.rlimcur0.2;
1212
1213 if (space > 1024*1024) space = 1024*1024;
1214 STACK_LEVEL_MAX = (rlim.rlim_cur â space) / sizeof(VALUE);
1215 }
1216 }
1217 #endif
1218 }(gc.c)
éèŠãªã®ã¯çãäžã®éšåã ãã ãã€ãŸãé©åœã«ããŒã«ã«å€æ°(ã¹ã¿ãã¯ã«ç¢ºä¿ããã)ãå®çŸ©ããŠãã®ã¢
ãã¬ã¹ã`rb_gc_stack_start`ãšããã`human68k`ã®ã³ãŒãã«ãã
`_SEND`ãšããã®ã¯ã³ã³ãã€ã©ã®ã©ã€ãã©ãªãã·ã¹ãã ãå®çŸ©ããå€æ°ã ããã
åœç¶`Stack END`ã®ç¥ã§ããããšæ³åã§ããã
äžæ¹ãã®ããšã®`HAVE_GETRLIMIT`ã§ããã£ãŠããã³ãŒãã§ã¯ã¹ã¿ãã¯ã®é·ãã
調ã¹ãŠãŽãã§ãŽãã§ãšãã£ãŠããããã ãããã`rb_gc_mark_children()`ã§ã®
ã¹ã¿ãã¯æº¢ãé²æ¢ã®äžè²«ã§ãããç¡èŠããŠããã
次ã«ã¹ã¿ãã¯ã®å 端ãæ€åºãããã¯ã`STACK_END`ãèŠãã
⌠`STACK_END`
345 #ifdef C_ALLOCA
346 # define SET_STACK_END VALUE stack_end; alloca(0);
347 # define STACK_END (&stack_end)
348 #else
349 # if defined(GNUC) && defined(USE_BUILTIN_FRAME_ADDRESS)
350 # define SET_STACK_END VALUE *stack_end = __builtin_frame_address(0)
351 # else
352 # define SET_STACK_END VALUE *stack_end = alloca(1)
353 # endif
354 # define STACK_END (stack_end)
355 #endif(gc.c)
`SET_STACK_END`ãäžéãããã®ã§ããŸãäžçªäžã®å Žåããã`alloca()`ã¯ã¹ã¿ã
ã¯ã®å
端ã«é åãå²ãåœãŠãŠè¿ãã®ã§ããã®è¿ãå€ãšã¹ã¿ãã¯ã®å
端ã¢ãã¬ã¹
ã¯ããªãè¿ãã¯ãã ãããã§`alloca()`ã®è¿ãå€ã§ã¹ã¿ãã¯å
端ã®è¿äŒŒãšããã
次ã«æ»ã£ãŠäžçªäžãèŠããããã¯ã`C_ALLOCA`ãå®çŸ©ãããŠããå Žåã¯
`alloca()`ããã€ãã£ãã§å®çŸ©ãããŠãªãâŠâŠã€ãŸããäºæé¢æ°ãCã§å®çŸ©ãã
ãŠããããšã瀺ãããã®å Žåã¯`alloca()`ã¯å
éšã§`malloc()`ã§ã¡ã¢ãªã確ä¿ããŠ
ããã®ã§ãã£ããããã§ã¯ã¹ã¿ãã¯ã®äœçœ®ãåãã®ã«ã¯å
šã圹ã«ç«ããªããã
ãã§ã©ãããããšãããšãããŸå®è¡äžã®é¢æ°ã®ããŒã«ã«å€æ°(`stack_end`)ã
ã¹ã¿ãã¯ã®å
端ã«è¿ããšå€æããŠãã®ã¢ãã¬ã¹ã䜿ã(`&stack_end`)ã
ãŸããã®ã³ãŒãã«ã¯ãäœã«äœ¿ã£ãŠããã®ãããããããªã`alloca(0)`ãå
¥ã£ãŠ
ãããããã¯Cã§å®çŸ©ãã`alloca()`ã®æããã®ä»æ§ã§ããããªãé åããã§ã
ã¯ããŠè§£æŸããŠãããšããæå³ã§ãããã¡ããã©GCããã£ãŠãããã
`alloca()`ã®å²ãåœãŠãåãäžç·ã«è§£æŸããŠããããšããããã ãããããã
ãªãããã§ãããªãšããã«çŽãããŸããå¥ã®ãã¯ãã«å
¥ããŠãããã»ãããã
ãšæãã®ã ãâŠâŠã
ãããŠæåŸã«çãäžã®å Žåã`builtin_frame_address()`ã«ã€ããŠã
`GNUC__`ã¯`gcc`(GNUã®Cã³ã³ãã€ã©)ã§å®çŸ©ãããã·ã³ãã«ã§ããã
ããã䜿ã£ãŠéå®ããŠããã®ã ããã
ããã¯`gcc`çµã¿èŸŒã¿ã®æ¡åŒµåœä»€ã ã`builtin_frame_address(n)`㧠n ååã®
ã¹ã¿ãã¯ãã¬ãŒã ã®ã¢ãã¬ã¹ãåããã`builtin_frame_address(0)`ãªã
çŸåšã®ãã¬ãŒã ã®ã¢ãã¬ã¹ã ã
æåŸã¯å®éã«ã¹ã¿ãã¯ãããŒã¯ããé¢æ°`rb_gc_mark_locations()`ã§ããã
⌠`rb_gc_mark_locations()`
513 void
514 rb_gc_mark_locations(start, end)
515 VALUE *start, *end;
516 {
517 VALUE *tmp;
518 long n;
519
520 if (start > end) {
521 tmp = start;
522 start = end;
523 end = tmp;
524 }
525 n = end â start + 1;
526 mark_locations_array(start,n);
527 }(gc.c)
åºæ¬çã«ã¯é åãããŒã¯ããé¢æ°`mark_locations_array()`ã«ä»»ããã°ããã
ãã®é¢æ°ãããã®ã¯åŒæ°ãããŸã調ç¯ããããšã§ããããã®ãããªèª¿æŽã
å¿
èŠã«ãªãã®ã¯ããã·ã³ã¹ã¿ãã¯ã䌞ã³ãæ¹åã決ãŸã£ãŠããªãããã ã
äœäœã¢ãã¬ã¹ã«äŒžã³ãå Žåã¯`end`ã®ã»ããå°ããããé«äœã¢ãã¬ã¹ã«äŒžã³ã
å Žåã¯`start`ã®ã»ããå°ãããã ããã¢ãã¬ã¹ã®å°ããã»ãã`start`ã«ãªã
ããã«ããã§æããã®ã ã
æåŸã«ã€ã³ã¿ããªã¿çµã¿ãã¿ã®`VALUE`ã³ã³ãããããŒã¯ããã
⌠ãã®ä»ã®ã«ãŒã
1159 /* ç»é²ãããŠããã°ããŒãã«å€æ°ãããŒã¯ /
1160 for (list = global_List; list; list = listânext) {
1161 rb_gc_mark(listâvarptr);
1162 }
1163 rb_mark_end_proc();
1164 rb_gc_mark_global_tbl();
1165
1166 rb_mark_tbl(rb_class_tbl);
1167 rb_gc_mark_trap_list();
1168
1169 /* trueãfalseãªã©ã®ã€ã³ã¹ã¿ã³ã¹å€æ°ãããã°ãããããŒã¯ /
1170 rb_mark_generic_ivar_tbl();
1171
/ rubyã®ããŒãµã§äœ¿ãå€æ°ãããŒã¯(ããŒã¹äžã®ã¿) */
1172 rb_gc_mark_parser();(gc.c)
Cã®ã°ããŒãã«å€æ°ã«`VALUE`ãå
¥ããå Žåã¯`rb_gc_register_address()`ã§
ãã®ã¢ãã¬ã¹ããŠãŒã¶ã«ç»é²ããŠãããããšã«ãªã£ãŠããã`global_List`ã«
ãããä¿åãããŠããã®ã§ãå
šéšããŒã¯ããã
`rb_mark_end_proc()`ã¯Rubyã®`END`æãªã©ã§ç»é²ããã
ããã°ã©ã ã®çµäºæã«å®è¡ããã
æç¶ããªããžã§ã¯ãã®ããŒã¯(æ¬æžã§ã¯`END`æã¯æ±ããªã)ã
`rb_gc_mark_global_tbl()`ã¯ã°ããŒãã«å€æ°ã®ããŒãã«`rb_global_tbl`ã®
ããŒã¯(æ¬¡ç« ãå€æ°ãšå®æ°ãåç
§)ã
`rb_mark_tbl(rb_class_tbl)`ã¯åç« ã§ãã£ã`rb_class_tbl`ã®ããŒã¯ã
`rb_gc_mark_trap_list()`ã¯Rubyã®é¢æ°ã¡ãœãã`trap`ã§ç»é²ãã
æç¶ããªããžã§ã¯ãã®ããŒã¯(ã·ã°ãã«é¢ä¿ããããæ¬æžã§ã¯æ±ããªã)ã
`rb_mark_generic_ivar_tbl()`ã¯`true`ãªã©ã®éãã€ã³ã¿`VALUE`ã®ããã«
çšæãããã€ã³ã¹ã¿ã³ã¹å€æ°ããŒãã«ãããŒã¯ããã
`rb_gc_mark_parser()`ã¯ããŒãµã®ã»ãã³ãã£ãã¯ã¹ã¿ãã¯ãããŒã¯ãã
(ã»ãã³ãã£ãã¯ã¹ã¿ãã¯ã«ã€ããŠã¯ç¬¬äºéšãåç
§)ã
ãããŸã§ã§ããŒã¯ãã§ã€ãºã¯çµããã ã
ã¹ã€ãŒããã§ã€ãºã¯ããŒã¯ãããŠããªããªããžã§ã¯ããæ¢ããŠè§£æŸããŠããäœ
æ¥ã ãããããã¡ãã£ãšçç±ããã£ãŠ`T_NODE`åã®ãªããžã§ã¯ãã ãã¯ç¹å¥æ±ã
ãããŠããã次ã®ãšãããèŠãŠã»ããã
⌠`gc_sweep()`åé
846 static void
847 gc_sweep()
848 {
849 RVALUE p, *pend, *final_list;
850 int freed = 0;
851 int i, used = heaps_used;
852
853 if (ruby_in_compile && ruby_parser_stack_on_heap()) {
854 / yaccã®ã¹ã¿ãã¯ããã·ã³ã¹ã¿ãã¯äžã«ãªãå Žåã¯
855 ããŒã¹äžã¯NODEãååããŠã¯ãªããªã */
856 for (i = 0; i < used; i++) {
857 p = heaps[i]; pend = p + heaps_limits[i];
858 while (p < pend) {
859 if (!(pâas.basic.flags & FL_MARK) &&
BUILTIN_TYPE(p) == T_NODE)
860 rb_gc_mark((VALUE)p);
861 p++;
862 }
863 }
864 }(gc.c)
`NODE`ã¯ããŒãµã§ããã°ã©ã ãè¡šçŸããããã«äœ¿ããªããžã§ã¯ãã ã`NODE`ã¯ã³ã³
ãã€ã«äžã«ã¯`yacc`ãšããããŒã«ã®çšæããã¹ã¿ãã¯ã«çœ®ãããã®ã ãããã®ã¹
ã¿ãã¯ã¯ãã·ã³ã¹ã¿ãã¯äžã«ãããšã¯éããªããå
·äœçã«èšããšã
`ruby_parser_stack_on_heap()`ãåœã ãšãã·ã³ã¹ã¿ãã¯äžã«ãªãããšã瀺ãã
ãããšãã®å Žåã¯çæéäžã®`NODE`ããã£ããååãããŠããŸãå±éºãããã®ã§ã
ã³ã³ãã€ã«äž(`ruby_in_compile`)ã¯`T_NODE`åã®ãªããžã§ã¯ããç¡æ¡ä»¶ã«
ããŒã¯ããŠãååãããªãããã«ããã®ã§ããã
ãããŸã§æ¥ããããŒã¯ãããŠããªããªããžã§ã¯ãã¯å
šãŠè§£æŸã§ããããã«ãªãã
ãã解æŸåã«ããäžä»äºããªããã°ãªããªããRubyã§ã¯ãªããžã§ã¯ãã®è§£æŸã
ããã¯ã§ããããã«ãªã£ãŠããã®ã§ããããåŒã¶å¿
èŠãããããã®ããã¯ã
ãã¡ã€ãã©ã€ã¶(finalizer)ãšèšãã
⌠`gc_sweep()`äžç€
869 freelist = 0;
870 final_list = deferred_final_list;
871 deferred_final_list = 0;
872 for (i = 0; i < used; i++) {
873 int n = 0;
874
875 p = heaps[i]; pend = p + heaps_limits[i];
876 while (p < pend) {
877 if (!(pâas.basic.flags & FL_MARK)) {
878 (A) if (pâas.basic.flags) {
879 obj_free((VALUE)p);
880 }
881 (B) if (need_call_final && FL_TEST(p, FL_FINALIZE)) {
882 pâas.free.flags = FL_MARK; /* ããŒã¯ããããŸãŸæ®ã /
883 pâas.free.next = final_list;
884 final_list = p;
885 }
886 else {
887 pâas.free.flags = 0;
888 pâas.free.next = freelist;
889 freelist = p;
890 }
891 n++;
892 }
893 © else if (RBASICâflags == FL_MARK) {
894 / ãã¡ã€ãã©ã€ãºãå¿ èŠãªãªããžã§ã¯ãã /
895 / äœãããªãã§æŸã£ãŠãã */
896 }
897 else {
898 RBASICâflags &= ~FL_MARK;
899 }
900 p++;
901 }
902 freed += n;
903 }
904 if (freed < FREE_MIN) {
905 add_heap();
906 }
907 during_gc = 0;(gc.c)
ãªããžã§ã¯ãããŒãã端ããå
šãŠèŠãŠããã`FL_MARK`ãã©ã°ãç«ã£ãŠããªãã£
ãã`obj_free()`ã§è§£æŸãã(A)ã`obj_free()`ã§ã¯äŸãã°æååãªããžã§ã¯ãã
䜿ã`char[]`ãé
åãªããžã§ã¯ãã䜿ã`VALUE[]`ã解æŸããã ãã§ã
`RVALUE`æ§é äœã解æŸãããã¯ãªããã`basic.flags`ãå
šãããããªããã
ãã`obj_free()`ãåŒãã ããšã«ãã®æ§é äœãæäœããŠãèœã¡ãå¿é
ã¯ãªãã
ãªããžã§ã¯ãã解æŸããããšã`FL_FINALIZE`ãã©ã°ã«ãã£ãŠåå²ãã(B)ã
`FL_FINALIZE`ãç«ã£ãŠããããã®ãªããžã§ã¯ãã«å¯ŸããŠãã¡ã€ãã©ã€ã¶ãå®çŸ©
ãããŠããã®ã§`final_list`ã«ãç«ã£ãŠããªãã£ããããã«`freelist`ã«è¿œå ã
ãããŸããã¡ã€ãã©ã€ãºãããšãã¯`basic.flags`ã`FL_MARK`ã«ãããããã§æ§é
äœåãã©ã°(`T_STRING`ãªã©)ãã¯ãªã¢ãããã®ã§ãçããŠãããªããžã§ã¯ããš
åºå¥ãä»ãã
ããšã¯ãŸãšããŠãã¡ã€ãã©ã€ã¶ãå®è¡ããã°çµããã ãããã§ããã¡ã€ãã©ã€
ã¶ãåŒã¶ãšãã¯ããã¯å¯Ÿè±¡ãšãªã£ããªããžã§ã¯ãã¯æ¢ã«æ»ãã§ããããšã«æ³š
æããããã€ãŸããã¡ã€ãã©ã€ã¶å®è¡äžã«ãããã¯ãããããªããžã§ã¯ãã䜿
ãããšã¯ã§ããªãã
⌠`gc_sweep()`æ®ã
910 if (final_list) {
911 RVALUE *tmp;
912
913 if (rb_prohibit_interrupt || ruby_in_compile) {
914 deferred_final_list = final_list;
915 return;
916 }
917
918 for (p = final_list; p; p = tmp) {
919 tmp = pâas.free.next;
920 run_final((VALUE)p);
921 pâas.free.flags = 0;
922 pâas.free.next = freelist;
923 freelist = p;
924 }
925 }
926 }(gc.c)
åŸåã®`for`ãã¡ã€ã³ã®ãã¡ã€ãã©ã€ãºäœæ¥ã ãååã®`if`ã¯æ§ã
ãªçç±ã«ãã
Rubyããã°ã©ã ã«å®è¡ã移ããªãå Žåã ãããã§ãã¡ã€ãã©ã€ãºãé
ããã
ãªããžã§ã¯ãã¯å
çšã®ãªã¹ãã®çµè·¯Â©ã«åºãŠããã
æåŸã«å°ãéã話ããããããããŸã§ã¯`ruby`ã®ã¬ãŒããŒãžã³ã¬ã¯ã¿ããªããžã§ã¯ããååãã
ãããªãã決ããŠãããããŠãŒã¶ããæ瀺çã«ååãããããšãã§ãããã
ãã`rb_gc_force_recycle()`ã§ããã
⌠`rb_gc_force_recycle()`
928 void
929 rb_gc_force_recycle(p)
930 VALUE p;
931 {
932 RANYâas.free.flags = 0;
933 RANYâas.free.next = freelist;
934 freelist = RANY;
935 }(gc.c)
ä»çµã¿ã¯ããããããšã¯ãªããã第äºéšã»ç¬¬äžéšã§äœåºŠãåºäŒãããšã«ãªãã®ã§
玹ä»ããŠãããã
åã
ã®ãªããžã§ã¯ãã§å²ãããŠãé åãäŸãã°`String`ã®`char[]`ãªã©ãã¯ã¹ã€ãŒ
ããã§ã€ãºã®äžã§è§£æŸãããŠãããã`RVALUE`æ§é äœèªäœã解æŸããã³ãŒãã¯åº
ãŠããªãã£ãããŸããªããžã§ã¯ãããŒãã§ã䜿ã£ãŠããæ§é äœã®æ°ã®ç®¡çãªã©
ã¯ãã£ãŠããªãããšããããšã¯ã`ruby`ã®ãªããžã§ã¯ãé åã¯äžåºŠå²ãåœãŠãã
絶察ã«è§£æŸãããªãã®ã ã
äŸãã°çè
ãããŸäœã£ãŠããã¡ãŒã©ã¯500éã®ã¡ãŒã«ã®ã¹ã¬ãããæ§ç¯ãã
ãšãäžæçã«40Mãã€ããããé åã䜿ãã®ã ãããã®ããšGCãããŠå€§åã䜿ããªã
ãªã£ããšããŠããã£ãš40Mãã€ãå æãç¶ãããçè
ã®ãã·ã³ãã€ãããã®ãã€ãªã®
ã§40Mãã€ãããã䜿ããããšããã§ãªããšããªããããã£ãšèµ·åãã£ã±ãªãã®
ãµãŒããªã©ã§ãããèµ·ãããšåé¡ã«ãªãããšãããã ããã
ãã ã`free()`ããã°ã¡ã¢ãªäœ¿çšéãæžããšãéããªãããšã«ã¯çæãã¹ãã§ã
ããã¡ã¢ãªãOSã«è¿ããªãéãããã»ã¹ã®ã¡ã¢ãªäœ¿çšéã¯æžããªãããããŠ
`malloc()`ã®å®è£
ã«ãã£ãŠã¯`free()`ããŠãã¡ã¢ãªãOSã«è¿ãããªãããšã¯ãã
ããã
âŠâŠãšæžããŠããã®ã ãããªããšæ¬æžã®ç· åééã«`RVALUE`ã解æŸãããããã«
ãªã£ãŠããŸã£ããæ·»ä»CD-ROMã«ã¯ææ°çã®`ruby`ãå
¥ã£ãŠãããã`diff`ããŠ
èŠãŠã¿ãŠã»ãããâŠâŠãªããŠé
·ããªãã ã
ããŒã¯&ã¹ã€ãŒãã«ã¯ããªããžã§ã¯ãé åå
šäœãæäœã§ãäžåºŠãªããå¿
èŠã
ããããšãã匱ç¹ããã£ããäžä»£å¥GCãšããèãããã䜿ããšãã®åŒ±ç¹ãè£ã
ãå¯èœæ§ãããã
äžä»£å¥GCã®åºç€ã«ãªãã®ã¯ãã»ãšãã©ã®ãªããžã§ã¯ãã¯å¯¿åœãéåžžã«é·ãã
éåžžã«çããã®ã©ã¡ããã§ããããšããçµéšåã ããã®ç¹ã¯èªåã®æžããã
ã°ã©ã ã®ããšãã¡ãã£ãšèããŠã¿ãã°çŽåŸããããšæãã
ããŠããã®èŠåãèžãŸããŠèããŠã¿ããšãé·çããããªããžã§ã¯ãã¯æ¯åæ¯å
ããŒã¯ããŠã¹ã€ãŒãããªããŠããããããªããããšããçºæ³ãåºãŠããããã®
ãªããžã§ã¯ãã¯é·çãã ãªããšæã£ãããç¹å¥æ±ãã«ããŠGC察象ããå€ãã°ã
ãã®ã ããããšããŒã¯ã«ããŠãã¹ã€ãŒãã«ããŠããªããžã§ã¯ãã®æ°ãå§åçã«
æžããããšãã§ãããäŸãã°ç¹å®ã®GCã®ã¿ã€ãã³ã°ã§é·çãããŠãããªããžã§
ã¯ããååãå ããŠãããšããã°å¯Ÿè±¡ãªããžã§ã¯ãæ°ã¯ååã«ãªãã
ãã äžã€åé¡ããããäžä»£å¥GCã¯ãªããžã§ã¯ãã移åã§ããªããšéåžžã«ããã«
ããã®ã ããªãããšãããšãé·çããããªããžã§ã¯ãã¯å
çšæžãããšãããç¹
å¥æ±ããããªããšãããªãããã§ãããäžä»£å¥GCã¯æ±ããªããžã§ã¯ããæžãã
ãŠã³ã¹ããäžããããã ããããã®äºã€ã®äžä»£ã«ãããªããžã§ã¯ãããã£ã¡ã
åé¡ããŠãããªããšçµå±ã®ãšããäž¡æ¹ã察象ã«ããã®ãšå€ãããªããªã£ãŠããŸ
ãããŸãããã«`ruby`ã®GCã¯conservative GCã§ããããã
`is_pointer_to_heap()`ãåãããã«ãäœããªããã°ãªããªãããããé£ããã
ããã§ã©ããã£ãŠãã®åé¡ã解決ãããã ãâŠâŠæšå±±ç人ããã®æã«ãã£ãŠ
`ruby`ã®ããã®äžä»£å¥GCã®å®è£
ãå
¬éãããŠããã以äžã¯ãã®ããããåçš®ã®
åé¡ã«ã©ã察åŠããã®ããç°¡åã«ç€ºããŠããããšã«ãããããŸãä»åã¯
æšå±±ããã®ãåæã«ããããã®äžä»£å¥GCããããšè«æãæ·»ä»CD-ROMã«åé²ããŠ
ãã\footnote{æšå±±çäžä»£å¥GCãããã«ã€ããŠã¯æ·»ä»CD-ROMã®`doc/generational-gc.html`ããŸãåç
§ã®ããš}ã
ã§ã¯èª¬æã«å
¥ãã説æãããããããã«ã
é·çããããªããžã§ã¯ãããæ§äžä»£ãªããžã§ã¯ããã
çã寿åœã®ãªããžã§ã¯ãããæ°äžä»£ãªããžã§ã¯ãã
ãšåŒã¶ããšã«ãããã
æåã«ãæ倧ã®åé¡ã§ããæ§äžä»£ãªããžã§ã¯ãã®ç¹å¥æ±ãã«ã€ããŠããã®ç¹ã¯
æ°äžä»£ã®ãªããžã§ã¯ãã ãã`newlist`ãšãããªã³ã¯ãªã¹ãã«ã€ãªãããšã§è§£æ±º
ããŠããããŸããã®ãªã¹ãã¯`RVALUE`ã®èŠçŽ ãå¢ããããšã§å®çŸããã
第äºã«ãæ§äžä»£ã®ãªããžã§ã¯ããèŠä»ããæ¹æ³ã«ã€ããŠãããã¯ãšãŠãç°¡åã§ã
`newlist`ã§GCãããªãã£ããã®ã`newlist`ããå€ãã ãã ãã€ãŸãäžåGCãçã
æ®ããšæ§äžä»£ã®ãªããžã§ã¯ããšããŠæ±ãããã
第äžã«ãæ§äžä»£ããæ°äžä»£ãžã®åç
§ãæ€åºããæ¹æ³ã«ã€ããŠãäžä»£å¥GCã§ã¯ã
èšã£ãŠã¿ãã°ãæ§äžä»£ã®ãªããžã§ã¯ãã«ã¯ããŒã¯ãä»ãã£ã±ãªãã®ç¶æ
ã«ãªã
ããã ããããæ§äžä»£ããæ°äžä»£ãžãªã³ã¯ãåºãŠããå Žåããã®æ°äžä»£ã®
ãªããžã§ã¯ãã«ã¯ããŒã¯ãä»ããªããªã(å³11)ã
ããã§ã¯ãŸããã®ã§ãæ§äžä»£ã®ãªããžã§ã¯ãããæ°äžä»£ã®ãªããžã§ã¯ããåç
§
ããããã®ç¬éã«ãã®æ°äžä»£ã®ãªããžã§ã¯ãã¯
æ§äžä»£ã«ãªããªããã°ãããªããããã§ã©ã€ãã©ãªãä¿®æ£ãããããã
åç
§ãèµ·ããå¯èœæ§ã®ãããšããã«ã²ããããã§ãã¯ãå
¥ããããã«ããŠããã
ä»çµã¿ã®æŠèŠã¯ä»¥äžã§ããããã®ãããã¯åœå`ruby` 1.7ã«åãããŸããäºå®ã ã£
ãã®ã ãçµå±ãŸã åãããŸããŠããªãããé床ãåºãªãã£ãããšããã®ãçç±
ã ããã ã第äžç¹ã®ãåç
§å
šãã§ãã¯ãã®ã³ã¹ããå¹ããŠããã®ã§ã¯ãªããã
ãšããæšæž¬ããªãããŠãããã詳ããåå ã¯ãŸã ããããã£ãŠããªãã
`ruby`ã®GCã§ã³ã³ãã¯ã·ã§ã³ã¯ã§ããã ãããã`ruby`ã®`VALUE`ã¯
æ§é äœãžã®çŽã
ã€ã³ã¿ã§ãããããã³ã³ãã¯ã·ã§ã³ããŠæ§é äœã®ã¢ãã¬ã¹ãå€ãã£ããã
移åããæ§é äœãæããŠãã`VALUE`ãå
šãŠæžãæããªããšãããªãã
ãšããã`ruby`ã®GCã¯conservative GCãªã®ã§ããããæ¬åœã«`VALUE`ãã©ãããã
ããªãå Žåããããããããããªã®ã«ãã®å€ãæžãæããŠããŸã£ããããã
`VALUE`ã§ãªãã£ããšãã«ã¯ãšãã§ããªãããšã«ãªããã³ã³ãã¯ã·ã§ã³ãš
conservative GCã¯ãšãŠãçžæ§ãæªãã®ã ã
ã ããªããšãããŠå¯ŸçãèããŠã¿ããããŸã`VALUE`ããã€ã³ã¿ã§ãªã
ãªããžã§ã¯ãIDã«
ããæ¹æ³ãèãããã(å³12)ã`VALUE`ãšæ§é äœã®éã«äž
æéæ¥å±€ãæãæ¹æ³ã ããããªã`VALUE`ãæžãæããã«æžãã®ã§å®å¿ããŠæ§
é äœã移åã§ãããã ããã®ä»£åãšããŠã¢ã¯ã»ã¹é床ã¯é
ããªãããæ¡åŒµã©ã€
ãã©ãªã®äºææ§ããªããªãã
ããã§æ¬¡ã®æ¹æ³ãšããŠãã確å®ã«`VALUE`ã§ããããã€ã³ã¿ãã ãããã
æãããŠããæ§é äœã«éå®ããŠç§»åãããšããææ³ããã(å³13)ã
ãã®ææ³ãMostly-copying garbage collectionãšèšããæ®éã®ããã°
ã©ã ãªã`is_pointer_to_heap()`ãçã«ãªããªããžã§ã¯ãã¯ããããããã¯ãªã
ãããããªãã®ç¢ºçã§ãªããžã§ã¯ãæ§é äœã移åã§ããããšã«ãªãã
ããã«ããã«ãããæ§é äœã移åã§ãããšããããšã«ãªãã°ã
åæã«äžä»£å¥GCã®å®è£
ãç°¡åã«ãªããææŠããŠã¿ã䟡å€ã¯ããããã ã
ã¹ã¿ãã¯äžã®`VALUE`ã¯GCãé¢åãèŠãŠããããšæžããããããªãã°
ããŒã«ã«å€æ°ãšããŠ`VALUE`ã眮ããŠããã°ãã®`VALUE`ã¯ç¢ºå®ã«ããŒã¯ããã
ã¯ãã§ããããããçŸå®ã«ã¯æé©åã®åœ±é¿ã§å€æ°ãæ¶ããŠããŸãããšãããã
äŸãã°æ¬¡ã®ãããªå Žåã¯æ¶ããå¯èœæ§ãããã
VALUE str; str = rb_str_new2("..."); printf("%s\n", RSTRING(str)->ptr);
ãã®ã³ãŒãã§ã¯`str`èªäœã«ã¢ã¯ã»ã¹ããŠããªãã®ã§ãã³ã³ãã€ã©ã«ãã£ãŠã¯
`strâptr`ã ãã¡ã¢ãªã«æ®ããŠ`str`ã¯æ¶ããŠããŸãããšãããããããããš
`str`ãååãããŠèœã¡ããããããæã¯ä»æ¹ããªãã®ã§ã
volatile VALUE str;
ãšããã`volatile`ã¯Cã®äºçŽèªã§ããã®å€æ°ã«é¢ããæé©åãçŠæ¢ãã
å¹æããããRubyé¢ä¿ã®ã³ãŒãã§`volatile`ãä»ããŠããããŸãééããªã
GC察çãšæã£ãŠãããK&Rãèªãã ãšãã¯ããããªãã®äœã«äœ¿ããã ããã
ãšæã£ãŠããã®ã ãããŸãã`ruby`ã§ãããªã«å€§éã«èŠãããšã«ãªããšã¯
æããªãã£ãã
ããããããããšãããèŠããšconservative GCã®ããŠãŒã¶ãGCãæ°ã«ããªã
ãŠããããšãã謳ãæå¥ãããŸãåœãŠã«ãªããªãããã§ãããäžæã¯
ãKSMãšããSchemeã®GCã¯`volatile`ãå¿
èŠãªããããã
ãšãã話ããã£ãã®ã ãã
ã¢ã«ãŽãªãºã ã«ç©Žããã£ãŠçµå±`ruby`ã«ã¯é©çšã§ããªãããã ã
When will GC start?
There are three places where `rb_gc() ` is called internally of `gc.c`.
- `ruby_xmalloc()`
- `ruby_xrealloc()`
- `rb_newobj()`
`ruby_xmalloc()`ãš`ruby_xrealloc()`ã®å Žåã¯ã¡ã¢ãªå²ãåœãŠã«å€±æãããšãã ã
ããã§GCããã°ã¡ã¢ãªã解æŸãããŠãŸã䜿ããã¹ããŒã¹ãã§ãããããããªãã
`rb_newobj()`ãç¶æ³ã¯äŒŒãŠããŠã`freelist`ã空ã«ãªã£ããšãã«èµ·åããã
`gc.c`以å€ã§ãã€ã³ã¿ããªã¿å ã§`rb_gc()`ãåŒãã§ãããšãããäœãæãããã
ãŸã`io.c`ãš`dir.c`ã§ããã¡ã€ã«ãã£ã¹ã¯ãªãã¿ã足ããªããŠéããªãã£ããšã
ã«GCãèµ·åããã`IO`ãªããžã§ã¯ããGCãããã°ãã¡ã€ã«ãã¯ããŒãºãããŠ
ãã¡ã€ã«ãã£ã¹ã¯ãªãã¿ã空ããããããªãããšããç®è«èŠããã ã
`ruby.c`ã§ã¯ãã¡ã€ã«ãããŒãããããšã§`rb_gc()`ããããšããããã¹ã€ãŒãã®
ãšããã§æžãããšãããã³ã³ãã€ã«äžã«`NODE`ãGCã§ããªãã®ãè£ãããã§ããã
GCã®è©±ãçµãã£ãŠRubyãªããžã§ã¯ãã®çæãã解æŸãŸã§ãæ±ããããã«
ãªã£ãã®ã§ãããã§ãªããžã§ã¯ãã®çæã«ã€ããŠã®è©±ãããŠããããããã¯
GCãšã¯ããŸãé¢ä¿ãªãããããåç« ã§ãã£ãã¯ã©ã¹ã®è©±ã«å°ãé¢ã£ãŠããã
ãããŸã§äœåºŠããªããžã§ã¯ããçæããŠãããäŸãã°ãããªæ¹æ³ãããã
class C end C.new()
ãã®ãšã`C.new`ã¯ã©ããã£ãŠãªããžã§ã¯ããçæããŠããã®ã ãããã
ãŸã`C.new`ã¯å®éã«ã¯`Class#new`ã§ããããã®å®äœã¯ããã ã
⌠`rb_class_new_instance()`
725 VALUE
726 rb_class_new_instance(argc, argv, klass)
727 int argc;
728 VALUE *argv;
729 VALUE klass;
730 {
731 VALUE obj;
732
733 obj = rb_obj_alloc(klass);
734 rb_obj_call_init(obj, argc, argv);
735
736 return obj;
737 }(object.c)
`rb_obj_alloc()`ã¯`klass`ã«å¯ŸããŠ`allocate`ãšããã¡ãœãããåŒã¶ãã€ãŸ
ãããŸèª¬æããŠããäŸãªãã°`C.allocate`ãåŒã¶ã
ãã®ããã©ã«ãã¯`Class#allocate`ã§ããã®ãŸãå®äœã
`rb_class_allocate_instance()`ã§ããã
⌠`rb_class_allocate_instance()`
708 static VALUE
709 rb_class_allocate_instance(klass)
710 VALUE klass;
711 {
712 if (FL_TEST(klass, FL_SINGLETON)) {
713 rb_raise(rb_eTypeError,
âcanât create instance of virtual classâ);
714 }
715 if (rb_frame_last_func() != alloc) {
716 return rb_obj_alloc(klass);
717 }
718 else {
719 NEWOBJ;
720 OBJSETUP;
721 return (VALUE)obj;
722 }
723 }(object.c)
æåŸã®äžè¡ä»¥å€ã¯æ°ã«ããªããŠããããã®`NEWOBJ`ã¯ãããŸã§
ãäœåãåºãŠãããRubyã®ãªããžã§ã¯ããäœããšãã®ã€ãã£ãªã ã§ãããä»åºŠ
ã¯äžèº«ãèŠãŠã¿ããã
⌠`NEWOBJ`
274 #define NEWOBJ type obj = (type)rb_newobj()
275 #define OBJSETUP do {\
276 RBASICâflags = (t);\
277 RBASICâklass = ©;\
278 if (rb_safe_level() >= 3) FL_SET(obj, FL_TAINT);\
279 } while (0)(ruby.h)
`rb_newobj()`ã¯`RVALUE`ãäžã€`freelist`ããå€ããŠè¿ããŠãããé¢æ°ã ã£ãã
`NEWOBJ`ã«åã®ããŸãããå ãããã®ã«ãããªããšã
ããããŸã`OBJSETUP()`ã¯`struct RBasic`éšåãåæåãããã¯ãã§ããã
ãã¡ãã¯`FL_TAINT`ãã©ã°ãç«ãŠãã®ãå¿ããªãããã ãã«ãããšæã£ãŠ
ããã ããã
ããšã¯`rb_class_new_instance()`ã«æ»ã£ãŠ`rb_obj_call_init()`ãåŒã¶ããšã«ãª
ãããã®é¢æ°ãäœã£ãã°ããã®ãªããžã§ã¯ãã«å¯ŸããŠ`initialize`ãåŒã³åºããŠ
åæåã¯å®äºã§ããã
ãŸãšãããšä»¥äžã®ããã«ãªã£ãŠããã
SomeClass.new = Class#new (rb_class_new_instance) SomeClass.allocate = Class#allocate (rb_class_allocate_instance) SomeClass#initialize = Object#initialize (rb_obj_dummy)
ã¯ã©ã¹ã¡ãœããã®`allocate`ãç©ççãªåæåã`initialize`ãè«ççãªåæ
åãšèšã£ãŠãããããã®ãããªä»çµã¿âŠâŠã€ãŸããªããžã§ã¯ãçæã
`allocate`ã»`initialize`ã«åå²ãã`new`ãçµ±èœãããšããä»çµã¿ãã
ãã¢ãã±ãŒã·ã§ã³ãã¬ãŒã ã¯ãŒã¯ããšåŒãã§ããã
次ã¯æ¡åŒµã©ã€ãã©ãªã§å®çŸ©ããã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹çæã«ã€ããŠèŠãŠããã
ãŠãŒã¶å®çŸ©ãšèšãããã«ã¯ãã®æ§é äœã¯æ±ºãŸã£ãŠããªãããã§ããã®å²ãåœãŠ
ãããæããŠãããªããš`ruby`ã«ã¯ã©ããã£ãŠäœã£ãŠããã®ãããããªãããã
ãæããæ¹æ³ãèŠããã
ãŠãŒã¶å®çŸ©ã ãããšãªãã ãããšçæã®ä»çµã¿èªäœã¯ã¢ãã±ãŒã·ã§ã³ãã¬ãŒã
ã¯ãŒã¯ã«åŸãã°ãããã€ãŸãæ°ããã¯ã©ã¹`SomeClass`ãCã§å®çŸ©ãããšãã¯
`SomeClass.allocate`ãš`SomeClass#initialize`ã®äž¡æ¹ããªãŒããŒã©ã€ãããã
ãŸãã¯`allocate`ã®ã»ãããèŠãŠããããããã§ã¯ç©ççãªåæåãããã
äœãå²ãåœãŠãã°ããããšèšããšããŠãŒã¶å®çŸ©ã¯ã©ã¹ã®ã€ã³ã¹ã¿ã³ã¹ã¯
`struct RData`ãšããã¡ãã§çšæããæ§é äœã®çµã§ãã£ããä»®ã«ãã®æ§é äœã
`struct my`åãšããŠãããããã®`struct my`ãå
ã«`VALUE`ãäœãã«ã¯
`Data_Wrap_Struct()`ãšãããã¯ãã䜿ãã䜿ãããã¯ããã ã
struct my *ptr = malloc(sizeof(struct my)); /* é©åœã«ããŒãã«åã */ VALUE val = Data_Wrap_Struct(data_class, mark_f, free_f, ptr);
`data_class`ã`val`ã®æå±ããã¯ã©ã¹ã§ã`ptr`ãã©ããããããšããŠããã
ã€ã³ã¿ã ã`mark_f`ããã®æ§é äœãããŒã¯ããããã®é¢æ°(ãžã®ãã€ã³ã¿)ã
ãšèšã£ãŠã`ptr`èªäœãããŒã¯ããããã§ã¯ãã¡ãããªããŠã`ptr`ã®æãæ§é
äœã®äžã«`VALUE`ããããšãã«äœ¿ããã®ã ãäžæ¹ã®`free_f`ã¯`ptr`èªäœã解æŸ
ããããã«äœ¿ãé¢æ°ã§ãããã©ã¡ãã®é¢æ°ãåŒæ°ã¯`ptr`ã ããã®ãããã¯å°
ãæ»ã£ãŠããŒã¯ã®ã³ãŒããèªãã§ãããããšäžçºã§çŽåŸã§ãããšæãã
`Data_Wrap_Struct()`ã®äžèº«ãèŠãŠãããã
⌠`Data_Wrap_Struct()`
369 #define Data_Wrap_Struct(klass, mark, free, sval) \
370 rb_data_object_alloc(klass, sval, \
(RUBY_DATA_FUNC)mark, \
(RUBY_DATA_FUNC)free) 365 typedef void (RUBY_DATA_FUNC) _((void));(ruby.h)
`rb_data_object_alloc()`ã«ã»ãšãã©å§è²ãããŠããã
⌠`rb_data_object_alloc()`
310 VALUE
311 rb_data_object_alloc(klass, datap, dmark, dfree)
312 VALUE klass;
313 void *datap;
314 RUBY_DATA_FUNC dmark;
315 RUBY_DATA_FUNC dfree;
316 {
317 NEWOBJ;
318 OBJSETUP;
319 dataâdata = datap;
320 dataâdfree = dfree;
321 dataâdmark = dmark;
322
323 return (VALUE)data;
324 }(gc.c)
ãªããŠããšã¯ãªããéåžžã®ãªããžã§ã¯ããšåãã`NEWOBJ`ã䜿ã£ãŠ
`RVALUE`ãçšæããã¡ã³ããå
¥ããã ãã ã
ããã§`allocate`ã®è©±ã«æ»ããããããŸã§ã§`VALUE`ã¯äœããã®ã§ãããšã¯ããã
é©åœãªé¢æ°ã«å
¥ããŠ`rb_define_singleton_method()`ã§ã¯ã©ã¹ã«å®çŸ©ããŠ
ããã°ããã
次ã¯`initialize`ã ã`initialize`ã«éãããã¡ãœããã§ã¯ãã£ãäœã£ã`VALUE`ã
ã`struct my*`ãåãåºãæ¹æ³ãå¿
èŠã«ãªãã¯ãã ããã®ããã«ã¯
`Data_Get_Struct()`ãšãããã¯ãã䜿ãã
⌠`Data_Get_Struct()`
378 #define Data_Get_Struct(obj,type,sval) do {\
379 Check_Type(obj, T_DATA); \
380 sval = (type*)DATA_PTR(obj);\
381 } while (0) 360 #define DATA_PTR(dta) (RDATAâdata)(ruby.h)
èŠãŠã®éãã`RData`ã®ã¡ã³ããã(`struct my`ãžã®)ãã€ã³ã¿ãåãåºãã ã
ã§ãããç°¡åã ã`Check_Type()`ã¯æ§é äœåã®ãã§ãã¯ãããã ãã
ãšããããŸã§äœé£ãã¬é¡ã§èª¬æããŠããã®ã ããå®ã¯çŸåšã®ã¢ãã±ãŒã·ã§ã³ã
ã¬ãŒã ã¯ãŒã¯ã«ã¯èŽåœçãªåé¡ããããããŸã`allocate`ã§äœã£ããªããžã§ã¯ã
ã`initialize`ããã®ä»ã®ã¡ãœããã«åºãŠããããšããããšãèšã£ãããããã§
åãã¯ã©ã¹ã®`allocate`ã§äœã£ããªããžã§ã¯ããæž¡ã£ãŠããŠãããªããšéåžžã«å°
ãã¯ãã ãäŸãã°ããã©ã«ãã®`Object.allocate`(`Class#allocate`)ã§äœã£ã
ãªããžã§ã¯ãã`String`ã®ã¡ãœããã«æž¡ã£ãŠããŸã£ãããšãŠãå°ãããªããªã
`String`ã®ã¡ãœããã¯`struct RString`ã®æ§é äœããããããšä»®å®ããŠæžããŠãã
ã®ã«ãå®éã«ã¯`struct RObject`ã ããã ãããããããšãé²ãããã«ã¯ã
`C.allocate`ã§äœã£ããªããžã§ã¯ããªãã`C`ãããã®äžäœã¯ã©ã¹ã®ã¡ãœããã ã
ã«æž¡ãããã«ããªããã°ãªããªãã
ãã¡ããæ®éã«ãã£ãŠããã°ãããªãã`C.allocate`ãªãã¯ã©ã¹`C`ã®ã€ã³ã¹ã¿ã³
ã¹ãäœãããã ãããã¯ã©ã¹`C`ã®ã¡ãœãã以å€ã«ã¯æž¡ããªãã¯ãã ã
äŸå€ãšããŠ`Object`ã®ã¡ãœããã«ã¯æž¡ãå¯èœæ§ããããã
`Object`ã®ã¡ãœããã¯æ§é äœåã«äŸåããªãããæžããŠããã
ã ãæ®éã«ãããªãã£ããã©ãã ãããã`C.allocate`ã¯Rubyã¬ãã«ã«é²åºããŠ
ããã®ã§ããŸã 説æããŠããªãã`alias`ã ã®`super`ã ã®ã掻çšããŸãããš
`allocate`ã®å®çŸ©ãå¥ã®ã¯ã©ã¹ã«ç§»æ€ã§ããŠããŸãããããããšãã¯ã©ã¹ã¯
`String`ãªã®ã«æ¬åœã®æ§é äœåã¯`struct RObject`ããªããŠãªããžã§ã¯ãã
äœããŠããŸããã€ãŸãRubyã¬ãã«ãã奜ãæŸé¡`ruby`ãèœãšããã®ã ãããã¯
å°ãã
åé¡ã®æ ¹æºã¯`allocate`ãã¡ãœãããšããŠRubyã¬ãã«ã«é²åºããŠããããšã ã
éã«èšããš`allocate`ã®äžèº«ãã¡ãœãã以å€ã®æ段ã§ã¯ã©ã¹ã«å®çŸ©ããŠããã°
ãããããã§
rb_define_allocator(rb_cMy, my_allocate);
ãšããæãã®ä»£æ¿æ¡ãçŸåšè°è«ãããŠããã
埡æèŠã»åŸ¡ææ³ã»èª€æ®ã®ææãªã©ã¯
éæšå³°é <aamine@loveruby.net>
ãŸã§ãé¡ãããŸãã
Copyright © 2002-2004 Minero Aoki, All rights reserved.