Module: GC

Defined in:
(unknown)

Defined Under Namespace

Modules: Profiler

Constant Summary collapse

OPTS =

GC build options

opts = rb_ary_new()
INTERNAL_CONSTANTS =

Internal constants in the garbage collector.

gc_constants

Class Method Summary collapse

Class Method Details

.add_stress_to_classObject

Raises NoMemoryError when allocating an instance of the given classes.



9437
9438
9439
9440
9441
9442
9443
9444
9445
9446
9447
9448
9449
9450
9451
9452
# File 'ext/gc-4.0/gc/default/default.c', line 9437

static VALUE
rb_gcdebug_add_stress_to_class(int argc, VALUE *argv, VALUE self)
{
    rb_objspace_t *objspace = rb_gc_get_objspace();

    if (!stress_to_class) {
        set_stress_to_class(rb_ident_hash_new_with_size(argc));
    }

    for (int i = 0; i < argc; i++) {
        VALUE klass = argv[i];
        rb_hash_aset(stress_to_class, klass, Qtrue);
    }

    return self;
}

.auto_compactBoolean

Returns whether or not automatic compaction has been enabled.

Returns:

  • (Boolean)


9093
9094
9095
9096
9097
# File 'ext/gc-4.0/gc/default/default.c', line 9093

static VALUE
gc_get_auto_compact(VALUE _)
{
    return ruby_enable_autocompact ? Qtrue : Qfalse;
}

.auto_compact=(flag) ⇒ Object

Updates automatic compaction mode.

When enabled, the compactor will execute on every major collection.

Enabling compaction will degrade performance on major collections.



9062
9063
9064
9065
9066
9067
9068
9069
9070
9071
9072
9073
9074
9075
9076
9077
9078
9079
9080
9081
# File 'ext/gc-4.0/gc/default/default.c', line 9062

static VALUE
gc_set_auto_compact(VALUE _, VALUE v)
{
    GC_ASSERT(GC_COMPACTION_SUPPORTED);

    ruby_enable_autocompact = RTEST(v);

#if RGENGC_CHECK_MODE
    ruby_autocompact_compare_func = NULL;

    if (SYMBOL_P(v)) {
        ID id = RB_SYM2ID(v);
        if (id == rb_intern("empty")) {
            ruby_autocompact_compare_func = compare_free_slots;
        }
    }
#endif

    return v;
}

.compactHash

This function compacts objects together in Ruby's heap. It eliminates unused space (or fragmentation) in the heap by moving objects in to that unused space.

The returned hash contains statistics about the objects that were moved; see GC.latest_compact_info.

This method is only expected to work on CRuby.

To test whether GC compaction is supported, use the idiom:

GC.respond_to?(:compact)

Returns:

  • (Hash)


9184
9185
9186
9187
9188
9189
9190
9191
9192
9193
9194
9195
9196
# File 'ext/gc-4.0/gc/default/default.c', line 9184

static VALUE
gc_compact(VALUE self)
{
    rb_objspace_t *objspace = rb_gc_get_objspace();
    int full_marking_p = gc_config_full_mark_val;
    gc_config_full_mark_set(TRUE);

    /* Run GC with compaction enabled */
    rb_gc_impl_start(rb_gc_get_objspace(), true, true, true, true);
    gc_config_full_mark_set(full_marking_p);

    return gc_compact_stats(self);
}

.latest_compact_infoHash

Returns information about object moved in the most recent GC compaction.

The returned hash contains the following keys:

[considered] Hash containing the type of the object as the key and the number of objects of that type that were considered for movement. [moved] Hash containing the type of the object as the key and the number of objects of that type that were actually moved. [moved_up] Hash containing the type of the object as the key and the number of objects of that type that were increased in size. [moved_down] Hash containing the type of the object as the key and the number of objects of that type that were decreased in size.

Some objects can't be moved (due to pinning) so these numbers can be used to calculate compaction efficiency.

Returns:

  • (Hash)


9127
9128
9129
9130
9131
9132
9133
9134
9135
9136
9137
9138
9139
9140
9141
9142
9143
9144
9145
9146
9147
9148
9149
9150
9151
9152
9153
9154
9155
9156
9157
9158
9159
9160
9161
# File 'ext/gc-4.0/gc/default/default.c', line 9127

static VALUE
gc_compact_stats(VALUE self)
{
    rb_objspace_t *objspace = rb_gc_get_objspace();
    VALUE h = rb_hash_new();
    VALUE considered = rb_hash_new();
    VALUE moved = rb_hash_new();
    VALUE moved_up = rb_hash_new();
    VALUE moved_down = rb_hash_new();

    for (size_t i = 0; i < T_MASK; i++) {
        if (objspace->rcompactor.considered_count_table[i]) {
            rb_hash_aset(considered, type_sym(i), SIZET2NUM(objspace->rcompactor.considered_count_table[i]));
        }

        if (objspace->rcompactor.moved_count_table[i]) {
            rb_hash_aset(moved, type_sym(i), SIZET2NUM(objspace->rcompactor.moved_count_table[i]));
        }

        if (objspace->rcompactor.moved_up_count_table[i]) {
            rb_hash_aset(moved_up, type_sym(i), SIZET2NUM(objspace->rcompactor.moved_up_count_table[i]));
        }

        if (objspace->rcompactor.moved_down_count_table[i]) {
            rb_hash_aset(moved_down, type_sym(i), SIZET2NUM(objspace->rcompactor.moved_down_count_table[i]));
        }
    }

    rb_hash_aset(h, ID2SYM(rb_intern("considered")), considered);
    rb_hash_aset(h, ID2SYM(rb_intern("moved")), moved);
    rb_hash_aset(h, ID2SYM(rb_intern("moved_up")), moved_up);
    rb_hash_aset(h, ID2SYM(rb_intern("moved_down")), moved_down);

    return h;
}

.malloc_allocated_sizeInteger

Returns the size of memory allocated by malloc().

Only available if ruby was built with CALC_EXACT_MALLOC_SIZE.

Returns:

  • (Integer)


9381
9382
9383
9384
9385
9386
# File 'ext/gc-4.0/gc/default/default.c', line 9381

static VALUE
gc_malloc_allocated_size(VALUE self)
{
    rb_objspace_t *objspace = (rb_objspace_t *)rb_gc_get_objspace();
    return ULL2NUM(objspace->malloc_params.allocated_size);
}

.malloc_allocationsInteger

Returns the number of malloc() allocations.

Only available if ruby was built with CALC_EXACT_MALLOC_SIZE.

Returns:

  • (Integer)


9397
9398
9399
9400
9401
9402
# File 'ext/gc-4.0/gc/default/default.c', line 9397

static VALUE
gc_malloc_allocations(VALUE self)
{
    rb_objspace_t *objspace = (rb_objspace_t *)rb_gc_get_objspace();
    return ULL2NUM(objspace->malloc_params.allocations);
}

.remove_stress_to_classObject

No longer raises NoMemoryError when allocating an instance of the given classes.



9462
9463
9464
9465
9466
9467
9468
9469
9470
9471
9472
9473
9474
9475
9476
9477
9478
# File 'ext/gc-4.0/gc/default/default.c', line 9462

static VALUE
rb_gcdebug_remove_stress_to_class(int argc, VALUE *argv, VALUE self)
{
    rb_objspace_t *objspace = rb_gc_get_objspace();

    if (stress_to_class) {
        for (int i = 0; i < argc; ++i) {
            rb_hash_delete(stress_to_class, argv[i]);
        }

        if (rb_hash_size(stress_to_class) == 0) {
            stress_to_class = 0;
        }
    }

    return Qnil;
}

.verify_compaction_references(toward: nil, double_heap: false) ⇒ Hash

Verify compaction reference consistency.

This method is implementation specific. During compaction, objects that were moved are replaced with T_MOVED objects. No object should have a reference to a T_MOVED object after compaction.

This function expands the heap to ensure room to move all objects, compacts the heap to make sure everything moves, updates all references, then performs a full GC. If any object contains a reference to a T_MOVED object, that object should be pushed on the mark stack, and will make a SEGV.

Returns:

  • (Hash)


9245
9246
9247
9248
9249
9250
9251
9252
9253
9254
9255
9256
9257
9258
9259
9260
9261
9262
9263
9264
9265
9266
9267
9268
9269
9270
9271
9272
9273
9274
9275
9276
9277
9278
9279
9280
9281
9282
9283
9284
9285
9286
9287
9288
9289
9290
9291
9292
9293
9294
9295
9296
9297
9298
9299
9300
9301
9302
9303
9304
9305
9306
9307
9308
9309
9310
9311
9312
9313
9314
9315
9316
9317
9318
9319
9320
9321
9322
9323
9324
9325
9326
9327
9328
9329
9330
9331
9332
9333
9334
# File 'ext/gc-4.0/gc/default/default.c', line 9245

static VALUE
gc_verify_compaction_references(int argc, VALUE* argv, VALUE self)
{
    static ID keywords[3] = {0};
    if (!keywords[0]) {
        keywords[0] = rb_intern("toward");
        keywords[1] = rb_intern("double_heap");
        keywords[2] = rb_intern("expand_heap");
    }

    VALUE options;
    rb_scan_args_kw(rb_keyword_given_p(), argc, argv, ":", &options);

    VALUE arguments[3] = { Qnil, Qfalse, Qfalse };
    int kwarg_count = rb_get_kwargs(options, keywords, 0, 3, arguments);
    bool toward_empty = kwarg_count > 0 && SYMBOL_P(arguments[0]) && SYM2ID(arguments[0]) == rb_intern("empty");
    bool expand_heap = (kwarg_count > 1 && RTEST(arguments[1])) || (kwarg_count > 2 && RTEST(arguments[2]));

    rb_objspace_t *objspace = rb_gc_get_objspace();

    /* Clear the heap. */
    rb_gc_impl_start(objspace, true, true, true, false);

    unsigned int lev = RB_GC_VM_LOCK();
    {
        gc_rest(objspace);

        /* if both double_heap and expand_heap are set, expand_heap takes precedence */
        if (expand_heap) {
            struct desired_compaction_pages_i_data desired_compaction = {
                .objspace = objspace,
                .required_slots = {0},
            };
            /* Work out how many objects want to be in each size pool, taking account of moves */
            objspace_each_pages(objspace, desired_compaction_pages_i, &desired_compaction, TRUE);

            /* Find out which pool has the most pages */
            size_t max_existing_pages = 0;
            for (int i = 0; i < HEAP_COUNT; i++) {
                rb_heap_t *heap = &heaps[i];
                max_existing_pages = MAX(max_existing_pages, heap->total_pages);
            }

            /* Add pages to each size pool so that compaction is guaranteed to move every object */
            for (int i = 0; i < HEAP_COUNT; i++) {
                rb_heap_t *heap = &heaps[i];

                size_t pages_to_add = 0;
                /*
                 * Step 1: Make sure every pool has the same number of pages, by adding empty pages
                 * to smaller pools. This is required to make sure the compact cursor can advance
                 * through all of the pools in `gc_sweep_compact` without hitting the "sweep &
                 * compact cursors met" condition on some pools before fully compacting others
                 */
                pages_to_add += max_existing_pages - heap->total_pages;
                /*
                 * Step 2: Now add additional free pages to each size pool sufficient to hold all objects
                 * that want to be in that size pool, whether moved into it or moved within it
                 */
                objspace->heap_pages.allocatable_slots = desired_compaction.required_slots[i];
                while (objspace->heap_pages.allocatable_slots > 0) {
                    heap_page_allocate_and_initialize(objspace, heap);
                }
                /*
                 * Step 3: Add two more pages so that the compact & sweep cursors will meet _after_ all objects
                 * have been moved, and not on the last iteration of the `gc_sweep_compact` loop
                 */
                pages_to_add += 2;

                for (; pages_to_add > 0; pages_to_add--) {
                    heap_page_allocate_and_initialize_force(objspace, heap);
                }
            }
        }

        if (toward_empty) {
            objspace->rcompactor.compare_func = compare_free_slots;
        }
    }
    RB_GC_VM_UNLOCK(lev);

    rb_gc_impl_start(rb_gc_get_objspace(), true, true, true, true);

    rb_objspace_reachable_objects_from_root(root_obj_check_moved_i, objspace);
    objspace_each_objects(objspace, heap_check_moved_i, objspace, TRUE);

    objspace->rcompactor.compare_func = NULL;

    return gc_compact_stats(self);
}

.verify_internal_consistencynil

Verify internal consistency.

This method is implementation specific. Now this method checks generational consistency if RGenGC is supported.

Returns:

  • (nil)


9044
9045
9046
9047
9048
9049
# File 'ext/gc-4.0/gc/default/default.c', line 9044

static VALUE
gc_verify_internal_consistency_m(VALUE dummy)
{
    rb_gc_verify_internal_consistency();
    return Qnil;
}