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
9 changes: 8 additions & 1 deletion src/gc-interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,15 @@ JL_DLLEXPORT void jl_gc_set_max_memory(uint64_t max_mem);
JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t collection);
// Returns whether the thread with `tid` is a collector thread
JL_DLLEXPORT int gc_is_collector_thread(int tid) JL_NOTSAFEPOINT;
// Enables or disables automatic full (non-generational) collections.
// When disabled (on == 0), automatic collections will only be incremental
// (young generation only). Explicit full collections via jl_gc_collect(JL_GC_FULL)
// are still honored. Returns whether automatic full collections were previously enabled.
JL_DLLEXPORT int jl_gc_enable_auto_full_collection(int on);
// Returns whether automatic full (non-generational) collections are enabled.
JL_DLLEXPORT int jl_gc_auto_full_collection_is_enabled(void);
// Returns which GC implementation is being used and possibly its version according to the list of supported GCs
// NB: it should clearly identify the GC by including e.g. stock or mmtk as a substring.
// NB: it should clearly identify the GC by including e.g. 'stock' or 'mmtk' as a substring.
JL_DLLEXPORT const char* jl_gc_active_impl(void);
// Sweep Julia's stack pools and mtarray buffers. Note that this function has been added to the interface as
// each GC should implement it but it will most likely not be used by other code in the runtime.
Expand Down
12 changes: 12 additions & 0 deletions src/gc-mmtk.c
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,18 @@ JL_DLLEXPORT const char* jl_gc_active_impl(void) {
return mmtk_version;
}

JL_DLLEXPORT int jl_gc_enable_auto_full_collection(int on)
{
// MMTk does not currently support collection type control
return 1;
}

JL_DLLEXPORT int jl_gc_auto_full_collection_is_enabled(void)
{
return 1;
}


int64_t last_gc_total_bytes = 0;
int64_t last_live_bytes = 0; // live_bytes at last collection
int64_t live_bytes = 0;
Expand Down
16 changes: 16 additions & 0 deletions src/gc-stock.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ int prev_sweep_full = 1;
int current_sweep_full = 0;
int next_sweep_full = 0;
int under_pressure = 0;
int gc_disable_auto_full_sweep = 0; // when set, automatic full collections are inhibited

// Full collection heuristics
static int64_t live_bytes = 0;
Expand Down Expand Up @@ -3177,6 +3178,9 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) JL_NOTS
recollect = 1;
gc_record_full_sweep_reason(FULL_SWEEP_REASON_FORCED_FULL_SWEEP);
}
if (gc_disable_auto_full_sweep && collection != JL_GC_FULL) {
sweep_full = 0;
Copy link

@tz-lom tz-lom Feb 19, 2026

Choose a reason for hiding this comment

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

please take a note - we are monitoring content of gc_record_full_sweep_reason and gc_num during pre/post gc hooks to understand what runtime decided to do.
please make sure that we would be able to reconstruct that FULL GC scheduled but cancelled

Copy link

Choose a reason for hiding this comment

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

@gbaraldi
Hi Gabriel
I've noticed that you merged this PR without answering question above.
can you reply to that one?
To illustrate issue I've prepared small repo with two demo files that I've collected:
https://github.com/tz-lom/gctest

you can see that with auto_full_collection enabled it is impossible to tell that it FULL GC was not done (except from timing which is much lower, but that is not reliable source of knowledge).
Do I miss something or can I distinguish it differently?

On top of that, I think it would be nice to expose this interface to Julia too, we are controlling GC from Julia most of the time (as GC strategy varies per interface call)

Please reply

Copy link
Member Author

@gbaraldi gbaraldi Feb 27, 2026

Choose a reason for hiding this comment

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

Well, if you disabled full sweeps manually I guess you can query that for your instrumentation. (It's pretty tricky because the main heuristics always change the next GC. Not the current one). Also hypothetically, knowing that the GC would've run a full sweep but didn't because it was manually disabled can be useful to figure out if, when possible, a manual full GC should be ran.

As for the API, I'm slightly wary about adding a Julia level API for this to be back ported. If we like this feature we can add it for non released versions of Julia, but on 1.12 I feel more comfortable keeping this something one has to look for and ccall. In case we decide to go for a different API

}
// 5. start sweeping
uint64_t start_sweep_time = jl_hrtime();
JL_PROBE_GC_SWEEP_BEGIN(sweep_full);
Expand Down Expand Up @@ -4151,6 +4155,18 @@ JL_DLLEXPORT const char* jl_gc_active_impl(void) {
return "Built with stock GC";
}

JL_DLLEXPORT int jl_gc_enable_auto_full_collection(int on)
{
int prev = !gc_disable_auto_full_sweep;
gc_disable_auto_full_sweep = (on == 0);
return prev;
}

JL_DLLEXPORT int jl_gc_auto_full_collection_is_enabled(void)
{
return !gc_disable_auto_full_sweep;
}

#ifdef __cplusplus
}
#endif