builtin: expose gc_disable(), gc_enable(), gc_is_enabled(), in addition to the existing gc_collect() (#21002)

This commit is contained in:
Delyan Angelov 2024-03-12 17:03:33 +02:00 committed by GitHub
parent a023fe3264
commit a373bee98b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 92 additions and 4 deletions

View File

@ -134,13 +134,37 @@ fn C.GC_is_disabled() int
// protect memory block from being freed before this call
fn C.GC_reachable_here(voidptr)
// gc_collect explicitly performs a garbage collection run.
// Note, that garbage collections are done automatically when needed in most cases,
// so usually you should need to call that function often.
// gc_is_enabled() returns true, if the GC is enabled at runtime.
// See also gc_disable() and gc_enable().
pub fn gc_is_enabled() bool {
return 0 == C.GC_is_disabled()
}
// gc_collect explicitly performs a single garbage collection run.
// Note, that garbage collections, are done automatically, when needed in most cases,
// so usually you should NOT need to call gc_collect() often.
// Note that gc_collect() is a NOP with `-gc none`.
pub fn gc_collect() {
C.GC_gcollect()
}
// gc_enable explicitly enables the GC.
// Note, that garbage collections are done automatically, when needed in most cases,
// and also that by default the GC is on, so you do not need to enable it.
// See also gc_disable() and gc_collect().
// Note that gc_enable() is a NOP with `-gc none`.
pub fn gc_enable() {
C.GC_enable()
}
// gc_disable explicitly disables the GC. Do not forget to enable it again by calling gc_enable(),
// when your program is otherwise idle, and can afford it.
// See also gc_enable() and gc_collect().
// Note that gc_disable() is a NOP with `-gc none`.
pub fn gc_disable() {
C.GC_disable()
}
// for leak detection it is advisable to do explicit garbage collections
pub fn gc_check_leaks() {
$if gcboehm_leak ? {

View File

@ -24,8 +24,28 @@ fn C.GC_gcollect()
// When GC is not used, it is a NOP.
pub fn gc_check_leaks() {}
// gc_is_enabled() returns true, if the GC is enabled at runtime.
// It will always return false, with `-gc none`.
// See also gc_disable() and gc_enable().
pub fn gc_is_enabled() bool {
return false
}
// gc_enable explicitly enables the GC.
// Note, that garbage collections are done automatically, when needed in most cases,
// and also that by default the GC is on, so you do not need to enable it.
// See also gc_disable() and gc_collect().
// Note that gc_enable() is a NOP with `-gc none`.
pub fn gc_enable() {}
// gc_disable explicitly disables the GC. Do not forget to enable it again by calling gc_enable(),
// when your program is otherwise idle, and can afford it.
// See also gc_enable() and gc_collect().
// Note that gc_disable() is a NOP with `-gc none`.
pub fn gc_disable() {}
// gc_collect explicitly performs a garbage collection.
// When the GC is not on, it is a NOP.
// When the GC is not on, (with `-gc none`), it is a NOP.
pub fn gc_collect() {}
type FnGC_WarnCB = fn (msg &char, arg usize)

View File

@ -0,0 +1,44 @@
// The goal of this program, is to test V's garbage collector interaction with gc_disable(), gc_enable(), gc_collect() and `-gc none`.
// Note that this program is intended to be run on Linux, where /proc/PID/status exists.
// It should run on other platforms too, but the last columns of the output will be empty.
// Example invocation: `MAX_ITERATIONS=100 BLOCK_SIZE=1_000_000 v run gc.v` .
import os
const block_size = os.getenv_opt('BLOCK_SIZE') or { '1_000' }.int()
const max_iterations = os.getenv_opt('MAX_ITERATIONS') or { '40' }.int()
fn do_some_work_and_allocate_memory() u64 {
a := []u8{len: block_size, init: u8(index)}
mut s := u64(0)
for x in a {
s += x
}
return s
}
fn process_mem_stats(pid int) string {
lines := os.read_lines('/proc/${pid}/status') or { [] }
mut vals := map[string]string{}
for line in lines {
x := line.split(':')
vals[x[0]] = x[1]
}
return 'VmSize: ${vals['VmSize']} | VmRSS: ${vals['VmRSS']}'
}
fn main() {
println('BLOCK_SIZE: ${block_size:15}, MAX_ITERATIONS: ${max_iterations:5}, gc_is_enabled: ${gc_is_enabled()}')
gc_disable()
mypid := os.getpid()
for c := 0; c < max_iterations; c++ {
if c % 15 == 0 {
gc_enable()
}
gc_collect()
s := do_some_work_and_allocate_memory()
println('gc_is_enabled: ${gc_is_enabled():6}, c: ${c:5}, s: ${s:10}, gc_memory_use: ${gc_memory_use():10}, ${process_mem_stats(mypid):30}')
if c % 15 == 0 {
gc_disable()
}
}
}