Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions base/gcutils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,29 @@ Module with garbage collection utilities.
"""
module GC

# @enum-like structure
struct CollectionType
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity, what is the reason for not using an actual @enum?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gcutils.jl is included very early in the system image, before Enums.jl and having @enum.

x::Int
end
Base.cconvert(::Type{Cint}, collection::CollectionType) = Cint(collection.x)

const Auto = CollectionType(0)
const Full = CollectionType(1)
const Incremental = CollectionType(2)

"""
GC.gc()
GC.gc(full::Bool=true)
GC.gc(collection::CollectionType)

Perform garbage collection.
Perform garbage collection. The argument `full` determines whether a full, but more costly
collection is performed. Otherwise, heuristics are used to determine which type of
collection is needed. For exact control, pass an argument of type `CollectionType`.

!!! warning
Excessive use will likely lead to poor performance.
"""
gc(full::Bool=true) = ccall(:jl_gc_collect, Cvoid, (Int32,), full)
gc(full::Bool=true) = ccall(:jl_gc_collect, Cvoid, (Cint,), full)
gc(collection::CollectionType) = ccall(:jl_gc_collect, Cvoid, (Cint,), collection)

"""
GC.enable(on::Bool)
Expand Down
25 changes: 14 additions & 11 deletions src/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -778,7 +778,7 @@ void jl_gc_force_mark_old(jl_ptls_t ptls, jl_value_t *v) JL_NOTSAFEPOINT
static inline void maybe_collect(jl_ptls_t ptls)
{
if (ptls->gc_num.allocd >= 0 || gc_debug_check_other()) {
jl_gc_collect(0);
jl_gc_collect(JL_GC_AUTO);
}
else {
jl_gc_safepoint_(ptls);
Expand Down Expand Up @@ -2667,7 +2667,7 @@ static void jl_gc_queue_bt_buf(jl_gc_mark_cache_t *gc_cache, jl_gc_mark_sp_t *sp
size_t jl_maxrss(void);

// Only one thread should be running in this function
static int _jl_gc_collect(jl_ptls_t ptls, int full)
static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
{
combine_thread_gc_counts(&gc_num);

Expand Down Expand Up @@ -2697,7 +2697,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, int full)
if (gc_cblist_root_scanner) {
export_gc_state(ptls, &sp);
gc_invoke_callbacks(jl_gc_cb_root_scanner_t,
gc_cblist_root_scanner, (full));
gc_cblist_root_scanner, (collection));
import_gc_state(ptls, &sp);
}
gc_mark_loop(ptls, sp);
Expand Down Expand Up @@ -2775,12 +2775,14 @@ static int _jl_gc_collect(jl_ptls_t ptls, int full)
else if (live_bytes >= last_live_bytes) {
grown_heap_age++;
}
if ((full || large_frontier ||
if (collection == JL_GC_INCREMENTAL) {
sweep_full = 0;
} else if ((collection == JL_GC_FULL || large_frontier ||
((not_freed_enough || promoted_bytes >= gc_num.interval) &&
(promoted_bytes >= default_collect_interval || prev_sweep_full)) ||
grown_heap_age > 1) &&
gc_num.pause > 1) {
recollect = full;
recollect = (collection == JL_GC_FULL);
if (large_frontier)
gc_num.interval = last_long_collect_interval;
if (not_freed_enough || large_frontier) {
Expand Down Expand Up @@ -2869,7 +2871,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, int full)
return recollect;
}

JL_DLLEXPORT void jl_gc_collect(int full)
JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t collection)
{
jl_ptls_t ptls = jl_get_ptls_states();
if (jl_gc_disable_counter) {
Expand All @@ -2896,12 +2898,13 @@ JL_DLLEXPORT void jl_gc_collect(int full)
// no-op for non-threading
jl_gc_wait_for_the_world();
gc_invoke_callbacks(jl_gc_cb_pre_gc_t,
gc_cblist_pre_gc, (full));
gc_cblist_pre_gc, (collection));

if (!jl_gc_disable_counter) {
JL_LOCK_NOGC(&finalizers_lock);
if (_jl_gc_collect(ptls, full)) {
int ret = _jl_gc_collect(ptls, 0);
if (_jl_gc_collect(ptls, collection)) {
// recollect
int ret = _jl_gc_collect(ptls, JL_GC_AUTO);
(void)ret;
assert(!ret);
}
Expand All @@ -2922,7 +2925,7 @@ JL_DLLEXPORT void jl_gc_collect(int full)
ptls->in_finalizer = was_in_finalizer;
}
gc_invoke_callbacks(jl_gc_cb_post_gc_t,
gc_cblist_post_gc, (full));
gc_cblist_post_gc, (collection));
}

void gc_mark_queue_all_roots(jl_ptls_t ptls, jl_gc_mark_sp_t *sp)
Expand Down Expand Up @@ -3332,7 +3335,7 @@ JL_DLLEXPORT int jl_gc_enable_conservative_gc_support(void)
// properly. We don't have to worry about race conditions
// for this part, as allocation itself is unproblematic and
// a collection will wait for safepoints.
jl_gc_collect(1);
jl_gc_collect(JL_GC_FULL);
}
return result;
} else {
Expand Down
8 changes: 7 additions & 1 deletion src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -746,7 +746,13 @@ JL_DLLEXPORT int64_t jl_gc_total_bytes(void);
JL_DLLEXPORT uint64_t jl_gc_total_hrtime(void);
JL_DLLEXPORT int64_t jl_gc_diff_total_bytes(void);

JL_DLLEXPORT void jl_gc_collect(int);
typedef enum {
JL_GC_AUTO = 0, // use heuristics to determine the collection type
JL_GC_FULL = 1, // force a full collection
JL_GC_INCREMENTAL = 2, // force an incremental collection
} jl_gc_collection_t;

JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t);

JL_DLLEXPORT void jl_gc_add_finalizer(jl_value_t *v, jl_function_t *f);
JL_DLLEXPORT void jl_finalize(jl_value_t *o);
Expand Down
4 changes: 2 additions & 2 deletions src/staticdata.c
Original file line number Diff line number Diff line change
Expand Up @@ -1269,8 +1269,8 @@ static void jl_cleanup_serializer2(void);

static void jl_save_system_image_to_stream(ios_t *f)
{
jl_gc_collect(1); // full
jl_gc_collect(0); // incremental (sweep finalizers)
jl_gc_collect(JL_GC_FULL);
jl_gc_collect(JL_GC_INCREMENTAL); // sweep finalizers
JL_TIMING(SYSIMG_DUMP);
int en = jl_gc_enable(0);
jl_init_serializer2(1);
Expand Down
9 changes: 9 additions & 0 deletions test/misc.jl
Original file line number Diff line number Diff line change
Expand Up @@ -758,3 +758,12 @@ end
# Finalizer with immutable should throw
@test_throws ErrorException finalizer(x->nothing, 1)
@test_throws ErrorException finalizer(C_NULL, 1)


@testset "GC utilities" begin
GC.gc()
GC.gc(true); GC.gc(false)
GC.gc(GC.Auto); GC.gc(GC.Full); GC.gc(GC.Incremental)

GC.safepoint()
end