207
219
record->allocate_limit = malloc_limit; \
210
#define GC_PROF_SET_HEAP_INFO do {\
211
if (objspace->profile.run) {\
212
gc_profile_record *record = &objspace->profile.record[objspace->profile.count];\
213
record->heap_use_slots = heaps_used;\
214
record->heap_live_objects = live;\
215
record->heap_free_objects = freed; \
216
record->heap_total_objects = heaps_used * HEAP_OBJ_LIMIT;\
217
record->have_finalize = final_list ? Qtrue : Qfalse;\
218
record->heap_use_size = live * sizeof(RVALUE); \
219
record->heap_total_size = heaps_used * (HEAP_OBJ_LIMIT * sizeof(RVALUE));\
222
#define GC_PROF_SET_HEAP_INFO(record) do {\
223
live = objspace->heap.live_num;\
224
total = heaps_used * HEAP_OBJ_LIMIT;\
225
(record).heap_use_slots = heaps_used;\
226
(record).heap_live_objects = live;\
227
(record).heap_free_objects = total - live;\
228
(record).heap_total_objects = total;\
229
(record).have_finalize = deferred_final_list ? Qtrue : Qfalse;\
230
(record).heap_use_size = live * sizeof(RVALUE);\
231
(record).heap_total_size = total * sizeof(RVALUE);\
233
#define GC_PROF_INC_LIVE_NUM objspace->heap.live_num++
234
#define GC_PROF_DEC_LIVE_NUM objspace->heap.live_num--
223
236
#define INIT_GC_PROF_PARAMS double gc_time = 0;\
224
size_t count = objspace->profile.count
237
size_t count = objspace->profile.count, total = 0, live = 0
225
238
#define GC_PROF_MARK_TIMER_START
226
239
#define GC_PROF_MARK_TIMER_STOP
227
240
#define GC_PROF_SWEEP_TIMER_START
228
241
#define GC_PROF_SWEEP_TIMER_STOP
229
242
#define GC_PROF_SET_MALLOC_INFO
230
#define GC_PROF_SET_HEAP_INFO do {\
231
if (objspace->profile.run) {\
232
gc_profile_record *record = &objspace->profile.record[objspace->profile.count];\
233
record->heap_total_objects = heaps_used * HEAP_OBJ_LIMIT;\
234
record->heap_use_size = live * sizeof(RVALUE); \
235
record->heap_total_size = heaps_used * HEAP_SIZE;\
243
#define GC_PROF_SET_HEAP_INFO(record) do {\
244
live = objspace->heap.live_num;\
245
total = heaps_used * HEAP_OBJ_LIMIT;\
246
(record).heap_total_objects = total;\
247
(record).heap_use_size = live * sizeof(RVALUE);\
248
(record).heap_total_size = total * sizeof(RVALUE);\
250
#define GC_PROF_INC_LIVE_NUM
251
#define GC_PROF_DEC_LIVE_NUM
376
399
rb_objspace_t *objspace = malloc(sizeof(rb_objspace_t));
377
400
memset(objspace, 0, sizeof(*objspace));
378
malloc_limit = GC_MALLOC_LIMIT;
401
malloc_limit = initial_malloc_limit;
379
402
ruby_gc_stress = ruby_initial_gc_stress;
407
static void initial_expand_heap(rb_objspace_t *objspace);
410
rb_gc_set_params(void)
412
char *malloc_limit_ptr, *heap_min_slots_ptr, *free_min_ptr;
414
if (rb_safe_level() > 0) return;
416
malloc_limit_ptr = getenv("RUBY_GC_MALLOC_LIMIT");
417
if (malloc_limit_ptr != NULL) {
418
int malloc_limit_i = atoi(malloc_limit_ptr);
419
printf("malloc_limit=%d (%d)\n", malloc_limit_i, initial_malloc_limit);
420
if (malloc_limit_i > 0) {
421
initial_malloc_limit = malloc_limit_i;
425
heap_min_slots_ptr = getenv("RUBY_HEAP_MIN_SLOTS");
426
if (heap_min_slots_ptr != NULL) {
427
int heap_min_slots_i = atoi(heap_min_slots_ptr);
428
printf("heap_min_slots=%d (%d)\n", heap_min_slots_i, initial_heap_min_slots);
429
if (heap_min_slots_i > 0) {
430
initial_heap_min_slots = heap_min_slots_i;
431
initial_expand_heap(&rb_objspace);
435
free_min_ptr = getenv("RUBY_FREE_MIN");
436
if (free_min_ptr != NULL) {
437
int free_min_i = atoi(free_min_ptr);
438
printf("free_min=%d (%d)\n", free_min_i, initial_free_min);
439
if (free_min_i > 0) {
440
initial_free_min = free_min_i;
445
static void gc_sweep(rb_objspace_t *);
446
static void slot_sweep(rb_objspace_t *, struct heaps_slot *);
447
static void gc_clear_mark_on_sweep_slots(rb_objspace_t *);
385
450
rb_objspace_free(rb_objspace_t *objspace)
387
rb_objspace_call_finalizer(objspace);
452
gc_clear_mark_on_sweep_slots(objspace);
388
454
if (objspace->profile.record) {
389
455
free(objspace->profile.record);
390
456
objspace->profile.record = 0;
738
822
return vm_xmalloc(&rb_objspace, size);
826
xmalloc2_size(size_t n, size_t size)
828
size_t len = size * n;
829
if (n != 0 && size != len / n) {
830
rb_raise(rb_eArgError, "malloc: possible integer overflow");
742
836
ruby_xmalloc2(size_t n, size_t size)
744
size_t len = size * n;
745
if (n != 0 && size != len / n) {
746
rb_raise(rb_eArgError, "malloc: possible integer overflow");
748
return vm_xmalloc(&rb_objspace, len);
838
return vm_xmalloc(&rb_objspace, xmalloc2_size(n, size));
842
vm_xcalloc(rb_objspace_t *objspace, size_t count, size_t elsize)
847
size = xmalloc2_size(count, elsize);
848
size = vm_malloc_prepare(objspace, size);
850
TRY_WITH_GC(mem = calloc(1, size));
851
return vm_malloc_fixup(objspace, mem, size);
752
855
ruby_xcalloc(size_t n, size_t size)
754
void *mem = ruby_xmalloc2(n, size);
755
memset(mem, 0, n * size);
857
return vm_xcalloc(&rb_objspace, n, size);
957
init_heap(rb_objspace_t *objspace)
1071
add_heap_slots(rb_objspace_t *objspace, size_t add)
961
add = HEAP_MIN_SLOTS / HEAP_OBJ_LIMIT;
967
1075
if ((heaps_used + add) > heaps_length) {
968
allocate_heaps(objspace, heaps_used + add);
1076
allocate_sorted_heaps(objspace, heaps_used + add);
971
1079
for (i = 0; i < add; i++) {
972
1080
assign_heap_slot(objspace);
1085
init_heap(rb_objspace_t *objspace)
1087
add_heap_slots(objspace, HEAP_MIN_SLOTS / HEAP_OBJ_LIMIT);
1088
#ifdef USE_SIGALTSTACK
1090
/* altstack of another threads are allocated in another place */
1091
rb_thread_t *th = GET_THREAD();
1092
void *tmp = th->altstack;
1093
th->altstack = malloc(ALT_STACK_SIZE);
1094
free(tmp); /* free previously allocated area */
975
1099
objspace->profile.invoke_time = getrusage_time();
1100
finalizer_table = st_init_numtable();
1103
#if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
1105
initial_expand_heap(rb_objspace_t *objspace)
1107
size_t min_size = initial_heap_min_slots / HEAP_OBJ_LIMIT;
1109
if (min_size > heaps_used) {
1110
add_heap_slots(objspace, min_size - heaps_used);
980
1116
set_heaps_increment(rb_objspace_t *objspace)
1025
1182
RANY(obj)->file = rb_sourcefile();
1026
1183
RANY(obj)->line = rb_sourceline();
1185
GC_PROF_INC_LIVE_NUM;
1034
rb_fill_value_cache(rb_thread_t *th)
1036
rb_objspace_t *objspace = &rb_objspace;
1041
for (i=0; i<RUBY_VM_VALUE_CACHE_SIZE; i++) {
1042
VALUE v = rb_newobj_from_heap(objspace);
1044
th->value_cache[i] = v;
1045
RBASIC(v)->flags = FL_MARK;
1047
th->value_cache_ptr = &th->value_cache[0];
1048
rv = rb_newobj_from_heap(objspace);
1057
rb_objspace_t *objspace = &rb_objspace;
1064
#if USE_VALUE_CACHE || (defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE)
1065
rb_thread_t *th = GET_THREAD();
1068
VALUE v = *th->value_cache_ptr;
1070
#if defined(ENABLE_VM_OBJSPACE) && ENABLE_VM_OBJSPACE
1071
rb_objspace_t *objspace = th->vm->objspace;
1073
rb_objspace_t *objspace = &rb_objspace;
1079
rb_bug("object allocation during garbage collection phase");
1084
RBASIC(v)->flags = 0;
1085
th->value_cache_ptr++;
1088
v = rb_fill_value_cache(th);
1091
#if defined(GC_DEBUG)
1092
printf("cache index: %d, v: %p, th: %p\n",
1093
th->value_cache_ptr - th->value_cache, v, th);
1097
return rb_newobj_from_heap(objspace);
1102
1191
rb_node_newnode(enum node_type type, VALUE a0, VALUE a1, VALUE a2)
1855
gc_sweep(rb_objspace_t *objspace)
1857
RVALUE *p, *pend, *final_list;
1860
size_t live = 0, free_min = 0, do_heap_free = 0;
1862
do_heap_free = (size_t)((heaps_used * HEAP_OBJ_LIMIT) * 0.65);
1863
free_min = (size_t)((heaps_used * HEAP_OBJ_LIMIT) * 0.2);
1865
if (free_min < FREE_MIN) {
1866
do_heap_free = heaps_used * HEAP_OBJ_LIMIT;
1867
free_min = FREE_MIN;
2004
slot_sweep(rb_objspace_t *objspace, struct heaps_slot *sweep_slot)
2006
size_t free_num = 0, final_num = 0;
2008
RVALUE *free = freelist, *final = deferred_final_list;
2011
p = sweep_slot->slot; pend = p + sweep_slot->limit;
2013
if (!(p->as.basic.flags & FL_MARK)) {
2014
if (p->as.basic.flags &&
2015
((deferred = obj_free(objspace, (VALUE)p)) ||
2016
(FL_TEST(p, FL_FINALIZE)))) {
2018
p->as.free.flags = T_ZOMBIE;
2019
RDATA(p)->dfree = 0;
2021
p->as.free.flags |= FL_MARK;
2022
p->as.free.next = deferred_final_list;
2023
deferred_final_list = p;
2027
add_freelist(objspace, p);
2031
else if (BUILTIN_TYPE(p) == T_ZOMBIE) {
2032
/* objects to be finalized */
2033
/* do nothing remain marked */
2036
RBASIC(p)->flags &= ~FL_MARK;
2040
if (final_num + free_num == sweep_slot->limit &&
2041
objspace->heap.free_num > objspace->heap.do_heap_free) {
2044
for (pp = deferred_final_list; pp != final; pp = pp->as.free.next) {
2045
RDATA(pp)->dmark = (void (*)(void *))(VALUE)sweep_slot;
2046
pp->as.free.flags |= FL_SINGLETON; /* freeing page mark */
2048
sweep_slot->limit = final_num;
2049
freelist = free; /* cancel this page from freelist */
2050
unlink_heap_slot(objspace, sweep_slot);
2053
objspace->heap.free_num += free_num;
2055
objspace->heap.final_num += final_num;
2057
if (deferred_final_list) {
2058
rb_thread_t *th = GET_THREAD();
2060
RUBY_VM_SET_FINALIZER_INTERRUPT(th);
2066
ready_to_gc(rb_objspace_t *objspace)
2068
if (dont_gc || during_gc) {
2070
if (!heaps_increment(objspace)) {
2071
set_heaps_increment(objspace);
2072
heaps_increment(objspace);
2081
before_gc_sweep(rb_objspace_t *objspace)
1871
final_list = deferred_final_list;
1872
deferred_final_list = 0;
1873
for (i = 0; i < heaps_used; i++) {
1874
size_t free_num = 0, final_num = 0;
1875
RVALUE *free = freelist;
1876
RVALUE *final = final_list;
1879
if(heaps[i].finalize_flag) continue;
1881
p = heaps[i].slot; pend = p + heaps[i].limit;
1883
if (!(p->as.basic.flags & FL_MARK)) {
1884
if (p->as.basic.flags &&
1885
((deferred = obj_free(objspace, (VALUE)p)) ||
1886
((FL_TEST(p, FL_FINALIZE)) && need_call_final))) {
1888
p->as.free.flags = T_ZOMBIE;
1889
RDATA(p)->dfree = 0;
1891
p->as.free.flags |= FL_MARK;
1892
p->as.free.next = final_list;
1897
add_freelist(objspace, p);
1901
else if (BUILTIN_TYPE(p) == T_ZOMBIE) {
1902
/* objects to be finalized */
1903
/* do nothing remain marked */
1906
RBASIC(p)->flags &= ~FL_MARK;
1911
if (final_num + free_num == heaps[i].limit && freed > do_heap_free) {
1914
for (pp = final_list; pp != final; pp = pp->as.free.next) {
1915
RDATA(pp)->dmark = (void (*)())(VALUE)&heaps[i];
1916
pp->as.free.flags |= FL_SINGLETON; /* freeing page mark */
1918
heaps[i].limit = final_num;
1919
heaps[i].finalize_flag = TRUE;
1920
freelist = free; /* cancel this page from freelist */
2084
objspace->heap.do_heap_free = (size_t)((heaps_used * HEAP_OBJ_LIMIT) * 0.65);
2085
objspace->heap.free_min = (size_t)((heaps_used * HEAP_OBJ_LIMIT) * 0.2);
2086
if (objspace->heap.free_min < initial_free_min) {
2087
objspace->heap.do_heap_free = heaps_used * HEAP_OBJ_LIMIT;
2088
objspace->heap.free_min = initial_free_min;
2090
objspace->heap.sweep_slots = heaps;
2091
objspace->heap.free_num = 0;
2093
/* sweep unlinked method entries */
2094
if (GET_VM()->unlinked_method_entry_list) {
2095
rb_sweep_method_entry(GET_VM());
2100
after_gc_sweep(rb_objspace_t *objspace)
1926
2102
GC_PROF_SET_MALLOC_INFO;
2104
if (objspace->heap.free_num < objspace->heap.free_min) {
2105
set_heaps_increment(objspace);
2106
heaps_increment(objspace);
1927
2109
if (malloc_increase > malloc_limit) {
1928
malloc_limit += (size_t)((malloc_increase - malloc_limit) * (double)live / (live + freed));
1929
if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT;
2110
malloc_limit += (size_t)((malloc_increase - malloc_limit) * (double)objspace->heap.live_num / (heaps_used * HEAP_OBJ_LIMIT));
2111
if (malloc_limit < initial_malloc_limit) malloc_limit = initial_malloc_limit;
1931
2113
malloc_increase = 0;
1932
if (freed < free_min) {
1933
set_heaps_increment(objspace);
1934
heaps_increment(objspace);
2115
free_unused_heaps(objspace);
2119
lazy_sweep(rb_objspace_t *objspace)
2121
struct heaps_slot *next;
2123
heaps_increment(objspace);
2124
while (objspace->heap.sweep_slots) {
2125
next = objspace->heap.sweep_slots->next;
2126
slot_sweep(objspace, objspace->heap.sweep_slots);
2127
objspace->heap.sweep_slots = next;
2137
rest_sweep(rb_objspace_t *objspace)
2139
if (objspace->heap.sweep_slots) {
2140
while (objspace->heap.sweep_slots) {
2141
lazy_sweep(objspace);
2143
after_gc_sweep(objspace);
2147
static void gc_marks(rb_objspace_t *objspace);
2150
gc_lazy_sweep(rb_objspace_t *objspace)
2153
INIT_GC_PROF_PARAMS;
2155
if (objspace->flags.dont_lazy_sweep)
2156
return garbage_collect(objspace);
2159
if (!ready_to_gc(objspace)) return TRUE;
2162
GC_PROF_TIMER_START;
2163
GC_PROF_SWEEP_TIMER_START;
2165
if (objspace->heap.sweep_slots) {
2166
res = lazy_sweep(objspace);
2168
GC_PROF_SWEEP_TIMER_STOP;
2169
GC_PROF_SET_MALLOC_INFO;
2170
GC_PROF_TIMER_STOP(Qfalse);
2173
after_gc_sweep(objspace);
2176
if (heaps_increment(objspace)) {
2184
before_gc_sweep(objspace);
2185
if (objspace->heap.free_min > (heaps_used * HEAP_OBJ_LIMIT - objspace->heap.live_num)) {
2186
set_heaps_increment(objspace);
2189
GC_PROF_SWEEP_TIMER_START;
2190
if(!(res = lazy_sweep(objspace))) {
2191
after_gc_sweep(objspace);
2197
GC_PROF_SWEEP_TIMER_STOP;
2199
GC_PROF_TIMER_STOP(Qtrue);
2204
gc_sweep(rb_objspace_t *objspace)
2206
struct heaps_slot *next;
2208
before_gc_sweep(objspace);
2210
while (objspace->heap.sweep_slots) {
2211
next = objspace->heap.sweep_slots->next;
2212
slot_sweep(objspace, objspace->heap.sweep_slots);
2213
objspace->heap.sweep_slots = next;
2216
after_gc_sweep(objspace);
1938
/* clear finalization list */
1940
GC_PROF_SET_HEAP_INFO;
1941
deferred_final_list = final_list;
1942
RUBY_VM_SET_FINALIZER_INTERRUPT(GET_THREAD());
1945
free_unused_heaps(objspace);
1946
GC_PROF_SET_HEAP_INFO;
1951
2222
rb_gc_force_recycle(VALUE p)
1953
2224
rb_objspace_t *objspace = &rb_objspace;
1954
add_freelist(objspace, (RVALUE *)p);
2225
GC_PROF_DEC_LIVE_NUM;
2226
if (RBASIC(p)->flags & FL_MARK) {
2227
RANY(p)->as.free.flags = 0;
2230
add_freelist(objspace, (RVALUE *)p);
1957
2234
static inline void
2097
2377
#define GC_NOTIFY 0
2099
void rb_vm_mark(void *ptr);
2101
2379
#if STACK_GROW_DIRECTION < 0
2102
#define GET_STACK_BOUNDS(start, end, appendix) (start = STACK_END, end = STACK_START)
2380
#define GET_STACK_BOUNDS(start, end, appendix) ((start) = STACK_END, (end) = STACK_START)
2103
2381
#elif STACK_GROW_DIRECTION > 0
2104
#define GET_STACK_BOUNDS(start, end, appendix) (start = STACK_START, end = STACK_END+appendix)
2382
#define GET_STACK_BOUNDS(start, end, appendix) ((start) = STACK_START, (end) = STACK_END+(appendix))
2106
2384
#define GET_STACK_BOUNDS(start, end, appendix) \
2107
2385
((STACK_END < STACK_START) ? \
2108
(start = STACK_END, end = STACK_START) : (start = STACK_START, end = STACK_END+appendix))
2386
((start) = STACK_END, (end) = STACK_START) : ((start) = STACK_START, (end) = STACK_END+(appendix)))
2389
#define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
2112
2392
mark_current_machine_context(rb_objspace_t *objspace, rb_thread_t *th)
2114
rb_jmp_buf save_regs_gc_mark;
2396
VALUE v[sizeof(rb_jmp_buf) / sizeof(VALUE)];
2397
} save_regs_gc_mark;
2115
2398
VALUE *stack_start, *stack_end;
2117
2400
FLUSH_REGISTER_WINDOWS;
2118
2401
/* This assumes that all registers are saved into the jmp_buf (and stack) */
2119
rb_setjmp(save_regs_gc_mark);
2402
rb_setjmp(save_regs_gc_mark.j);
2122
2405
GET_STACK_BOUNDS(stack_start, stack_end, 1);
2124
mark_locations_array(objspace,
2125
(VALUE*)save_regs_gc_mark,
2126
sizeof(save_regs_gc_mark) / sizeof(VALUE));
2407
mark_locations_array(objspace, save_regs_gc_mark.v, numberof(save_regs_gc_mark.v));
2128
2409
rb_gc_mark_locations(stack_start, stack_end);
2130
2411
rb_gc_mark_locations(th->machine_register_stack_start, th->machine_register_stack_end);
2132
2413
#if defined(__mc68000__)
2133
mark_locations_array((VALUE*)((char*)STACK_END + 2),
2414
mark_locations_array(objspace, (VALUE*)((char*)STACK_END + 2),
2134
2415
(STACK_START - STACK_END));
2138
void rb_gc_mark_encodings(void);
2141
garbage_collect(rb_objspace_t *objspace)
2420
gc_clear_mark_on_sweep_slots(rb_objspace_t *objspace)
2422
struct heaps_slot *scan;
2425
if (objspace->heap.sweep_slots) {
2426
while (heaps_increment(objspace));
2427
while (objspace->heap.sweep_slots) {
2428
scan = objspace->heap.sweep_slots;
2429
p = scan->slot; pend = p + scan->limit;
2431
if (p->as.free.flags & FL_MARK && BUILTIN_TYPE(p) != T_ZOMBIE) {
2432
p->as.basic.flags &= ~FL_MARK;
2436
objspace->heap.sweep_slots = objspace->heap.sweep_slots->next;
2442
gc_marks(rb_objspace_t *objspace)
2143
2444
struct gc_list *list;
2144
2445
rb_thread_t *th = GET_THREAD();
2145
INIT_GC_PROF_PARAMS;
2147
if (GC_NOTIFY) printf("start garbage_collect()\n");
2153
if (dont_gc || during_gc) {
2155
if (!heaps_increment(objspace)) {
2156
set_heaps_increment(objspace);
2157
heaps_increment(objspace);
2446
GC_PROF_MARK_TIMER_START;
2448
objspace->heap.live_num = 0;
2163
2449
objspace->count++;
2165
GC_PROF_TIMER_START;
2166
GC_PROF_MARK_TIMER_START;
2452
gc_clear_mark_on_sweep_slots(objspace);
2169
2456
init_mark_stack(objspace);
2171
2458
th->vm->self ? rb_gc_mark(th->vm->self) : rb_vm_mark(th->vm);
2173
if (finalizer_table) {
2174
mark_tbl(objspace, finalizer_table, 0);
2460
mark_tbl(objspace, finalizer_table, 0);
2177
2461
mark_current_machine_context(objspace, th);
2179
rb_gc_mark_threads();
2180
2463
rb_gc_mark_symbols();
2181
2464
rb_gc_mark_encodings();
2684
3011
/* run finalizers */
2685
if (finalizer_table) {
2687
/* XXX: this loop will make no sense */
2688
/* because mark will not be removed */
2689
finalize_deferred(objspace);
2690
mark_tbl(objspace, finalizer_table, 0);
2691
st_foreach(finalizer_table, chain_finalized_object,
2692
(st_data_t)&deferred_final_list);
2693
} while (deferred_final_list);
2694
/* force to run finalizer */
2695
while (finalizer_table->num_entries) {
2696
struct force_finalize_list *list = 0;
2697
st_foreach(finalizer_table, force_chain_object, (st_data_t)&list);
2699
struct force_finalize_list *curr = list;
2700
run_finalizer(objspace, curr->obj, rb_obj_id(curr->obj), curr->table);
2701
st_delete(finalizer_table, (st_data_t*)&curr->obj, 0);
3012
gc_clear_mark_on_sweep_slots(objspace);
3015
/* XXX: this loop will make no sense */
3016
/* because mark will not be removed */
3017
finalize_deferred(objspace);
3018
mark_tbl(objspace, finalizer_table, 0);
3019
st_foreach(finalizer_table, chain_finalized_object,
3020
(st_data_t)&deferred_final_list);
3021
} while (deferred_final_list);
3022
/* force to run finalizer */
3023
while (finalizer_table->num_entries) {
3024
struct force_finalize_list *list = 0;
3025
st_foreach(finalizer_table, force_chain_object, (st_data_t)&list);
3027
struct force_finalize_list *curr = list;
3028
run_finalizer(objspace, rb_obj_id(curr->obj), curr->table);
3029
st_delete(finalizer_table, (st_data_t*)&curr->obj, 0);
2706
st_free_table(finalizer_table);
2707
finalizer_table = 0;
2709
3035
/* finalizers are part of garbage collection */
2711
3038
/* run data object's finalizers */
2712
3039
for (i = 0; i < heaps_used; i++) {
2713
p = heaps[i].slot; pend = p + heaps[i].limit;
3040
p = objspace->heap.sorted[i].start; pend = objspace->heap.sorted[i].end;
2714
3041
while (p < pend) {
2715
3042
if (BUILTIN_TYPE(p) == T_DATA &&
2716
3043
DATA_PTR(p) && RANY(p)->as.data.dfree &&
2717
RANY(p)->as.basic.klass != rb_cThread && RANY(p)->as.basic.klass != rb_cMutex) {
3044
!rb_obj_is_thread((VALUE)p) && !rb_obj_is_mutex((VALUE)p) ) {
2718
3045
p->as.free.flags = 0;
2719
3046
if (RTYPEDDATA_P(p)) {
2720
RDATA(p)->dfree = RANY(p)->as.typeddata.type->dfree;
3047
RDATA(p)->dfree = RANY(p)->as.typeddata.type->function.dfree;
2722
if ((long)RANY(p)->as.data.dfree == -1) {
3049
if (RANY(p)->as.data.dfree == (RUBY_DATA_FUNC)-1) {
2723
3050
xfree(DATA_PTR(p));
2725
3052
else if (RANY(p)->as.data.dfree) {
2998
3329
return UINT2NUM((&rb_objspace)->count);
3336
* Returns a Hash containing information about the GC.
3338
* The hash includes information about internal statistics about GC such as:
3343
* :heap_length => 77,
3344
* :heap_increment => 0,
3345
* :heap_live_num => 23287,
3346
* :heap_free_num => 8115,
3347
* :heap_final_num => 0,
3350
* The contents of the hash are implementation defined and may be changed in
3353
* This method is only expected to work on C Ruby.
3358
gc_stat(int argc, VALUE *argv, VALUE self)
3360
rb_objspace_t *objspace = &rb_objspace;
3363
if (rb_scan_args(argc, argv, "01", &hash) == 1) {
3364
if (TYPE(hash) != T_HASH)
3365
rb_raise(rb_eTypeError, "non-hash given");
3369
hash = rb_hash_new();
3372
rest_sweep(objspace);
3374
rb_hash_aset(hash, ID2SYM(rb_intern("count")), SIZET2NUM(objspace->count));
3376
/* implementation dependent counters */
3377
rb_hash_aset(hash, ID2SYM(rb_intern("heap_used")), SIZET2NUM(objspace->heap.used));
3378
rb_hash_aset(hash, ID2SYM(rb_intern("heap_length")), SIZET2NUM(objspace->heap.length));
3379
rb_hash_aset(hash, ID2SYM(rb_intern("heap_increment")), SIZET2NUM(objspace->heap.increment));
3380
rb_hash_aset(hash, ID2SYM(rb_intern("heap_live_num")), SIZET2NUM(objspace->heap.live_num));
3381
rb_hash_aset(hash, ID2SYM(rb_intern("heap_free_num")), SIZET2NUM(objspace->heap.free_num));
3382
rb_hash_aset(hash, ID2SYM(rb_intern("heap_final_num")), SIZET2NUM(objspace->heap.final_num));
3001
3387
#if CALC_EXACT_MALLOC_SIZE
3046
3432
prof = rb_hash_new();
3047
3433
rb_hash_aset(prof, ID2SYM(rb_intern("GC_TIME")), DBL2NUM(objspace->profile.record[i].gc_time));
3048
3434
rb_hash_aset(prof, ID2SYM(rb_intern("GC_INVOKE_TIME")), DBL2NUM(objspace->profile.record[i].gc_invoke_time));
3049
rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_USE_SIZE")), rb_uint2inum(objspace->profile.record[i].heap_use_size));
3050
rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_TOTAL_SIZE")), rb_uint2inum(objspace->profile.record[i].heap_total_size));
3051
rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_TOTAL_OBJECTS")), rb_uint2inum(objspace->profile.record[i].heap_total_objects));
3435
rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_USE_SIZE")), SIZET2NUM(objspace->profile.record[i].heap_use_size));
3436
rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_TOTAL_SIZE")), SIZET2NUM(objspace->profile.record[i].heap_total_size));
3437
rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_TOTAL_OBJECTS")), SIZET2NUM(objspace->profile.record[i].heap_total_objects));
3438
rb_hash_aset(prof, ID2SYM(rb_intern("GC_IS_MARKED")), objspace->profile.record[i].is_marked);
3052
3439
#if GC_PROFILE_MORE_DETAIL
3053
3440
rb_hash_aset(prof, ID2SYM(rb_intern("GC_MARK_TIME")), DBL2NUM(objspace->profile.record[i].gc_mark_time));
3054
3441
rb_hash_aset(prof, ID2SYM(rb_intern("GC_SWEEP_TIME")), DBL2NUM(objspace->profile.record[i].gc_sweep_time));
3055
rb_hash_aset(prof, ID2SYM(rb_intern("ALLOCATE_INCREASE")), rb_uint2inum(objspace->profile.record[i].allocate_increase));
3056
rb_hash_aset(prof, ID2SYM(rb_intern("ALLOCATE_LIMIT")), rb_uint2inum(objspace->profile.record[i].allocate_limit));
3057
rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_USE_SLOTS")), rb_uint2inum(objspace->profile.record[i].heap_use_slots));
3058
rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_LIVE_OBJECTS")), rb_uint2inum(objspace->profile.record[i].heap_live_objects));
3059
rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_FREE_OBJECTS")), rb_uint2inum(objspace->profile.record[i].heap_free_objects));
3442
rb_hash_aset(prof, ID2SYM(rb_intern("ALLOCATE_INCREASE")), SIZET2NUM(objspace->profile.record[i].allocate_increase));
3443
rb_hash_aset(prof, ID2SYM(rb_intern("ALLOCATE_LIMIT")), SIZET2NUM(objspace->profile.record[i].allocate_limit));
3444
rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_USE_SLOTS")), SIZET2NUM(objspace->profile.record[i].heap_use_slots));
3445
rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_LIVE_OBJECTS")), SIZET2NUM(objspace->profile.record[i].heap_live_objects));
3446
rb_hash_aset(prof, ID2SYM(rb_intern("HEAP_FREE_OBJECTS")), SIZET2NUM(objspace->profile.record[i].heap_free_objects));
3060
3447
rb_hash_aset(prof, ID2SYM(rb_intern("HAVE_FINALIZE")), objspace->profile.record[i].have_finalize);
3062
3449
rb_ary_push(gc_profile, prof);
3083
3469
rb_objspace_t *objspace = &rb_objspace;
3088
3474
record = gc_profile_record_get();
3089
3475
if (objspace->profile.run && objspace->profile.count) {
3090
3476
result = rb_sprintf("GC %d invokes.\n", NUM2INT(gc_count(0)));
3091
3478
rb_str_cat2(result, "Index Invoke Time(sec) Use Size(byte) Total Size(byte) Total Object GC Time(ms)\n");
3092
3479
for (i = 0; i < (int)RARRAY_LEN(record); i++) {
3093
3480
VALUE r = RARRAY_PTR(record)[i];
3094
rb_str_catf(result, "%5d %19.3f %20d %20d %20d %30.20f\n",
3095
i+1, NUM2DBL(rb_hash_aref(r, ID2SYM(rb_intern("GC_INVOKE_TIME")))),
3096
NUM2INT(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_USE_SIZE")))),
3097
NUM2INT(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_TOTAL_SIZE")))),
3098
NUM2INT(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_TOTAL_OBJECTS")))),
3481
#if !GC_PROFILE_MORE_DETAIL
3482
if (rb_hash_aref(r, ID2SYM(rb_intern("GC_IS_MARKED")))) {
3484
rb_str_catf(result, "%5d %19.3f %20"PRIuSIZE" %20"PRIuSIZE" %20"PRIuSIZE" %30.20f\n",
3485
index++, NUM2DBL(rb_hash_aref(r, ID2SYM(rb_intern("GC_INVOKE_TIME")))),
3486
(size_t)NUM2SIZET(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_USE_SIZE")))),
3487
(size_t)NUM2SIZET(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_TOTAL_SIZE")))),
3488
(size_t)NUM2SIZET(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_TOTAL_OBJECTS")))),
3099
3489
NUM2DBL(rb_hash_aref(r, ID2SYM(rb_intern("GC_TIME"))))*1000);
3490
#if !GC_PROFILE_MORE_DETAIL
3101
3494
#if GC_PROFILE_MORE_DETAIL
3102
3495
rb_str_cat2(result, "\n\n");
3103
3496
rb_str_cat2(result, "More detail.\n");
3104
3497
rb_str_cat2(result, "Index Allocate Increase Allocate Limit Use Slot Have Finalize Mark Time(ms) Sweep Time(ms)\n");
3105
3499
for (i = 0; i < (int)RARRAY_LEN(record); i++) {
3106
3500
VALUE r = RARRAY_PTR(record)[i];
3107
rb_str_catf(result, "%5d %17d %17d %9d %14s %25.20f %25.20f\n",
3108
i+1, NUM2INT(rb_hash_aref(r, ID2SYM(rb_intern("ALLOCATE_INCREASE")))),
3109
NUM2INT(rb_hash_aref(r, ID2SYM(rb_intern("ALLOCATE_LIMIT")))),
3110
NUM2INT(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_USE_SLOTS")))),
3501
rb_str_catf(result, "%5d %17"PRIuSIZE" %17"PRIuSIZE" %9"PRIuSIZE" %14s %25.20f %25.20f\n",
3502
index++, (size_t)NUM2SIZET(rb_hash_aref(r, ID2SYM(rb_intern("ALLOCATE_INCREASE")))),
3503
(size_t)NUM2SIZET(rb_hash_aref(r, ID2SYM(rb_intern("ALLOCATE_LIMIT")))),
3504
(size_t)NUM2SIZET(rb_hash_aref(r, ID2SYM(rb_intern("HEAP_USE_SLOTS")))),
3111
3505
rb_hash_aref(r, ID2SYM(rb_intern("HAVE_FINALIZE")))? "true" : "false",
3112
3506
NUM2DBL(rb_hash_aref(r, ID2SYM(rb_intern("GC_MARK_TIME"))))*1000,
3113
3507
NUM2DBL(rb_hash_aref(r, ID2SYM(rb_intern("GC_SWEEP_TIME"))))*1000);