Feature #18143
closedAdd a new method to change GC.stress only in the given block such as GC.with_stress(flag) {...}
Description
GC.stress = true
is useful for detecting GC related crashes. We can use it for debugging GC related problems and testing the problem is solved.
Generally, we need to enable stress mode before the target code block and disable stress mode after the target code block:
GC.stress = true
# ... something buggy codes ...
GC.stress = false
Or we just enable stress mode before the target code block when the target code block causes a crash:
GC.stress = true
# ... something crash codes ...
In test code, we must disable stress mode because stress mode slows down test execution:
def test_gc
GC.stress = true
# ... GC related code ...
ensure
GC.stress = false
end
We have an utility method in CRuby's test utility: EnvUtil.#under_gc_stress
:
def under_gc_stress(stress = true)
stress, GC.stress = GC.stress, stress
yield
ensure
GC.stress = stress
end
module_function :under_gc_stress
This feature is useful not only CRuby's test but also other libraries test and debugging a program that has a GC related problem.
How about adding a new singleton method that changes stress mode only in the given block? If we have the method, we don't need to implement a small utility method multiple times for the feature.
API candidates:
GC.with_stress(flag) {...}
:
module GC
def self.with_stress(flag)
flag_old = stress
self.stress = flag
yield
ensure
self.stress = flag_old
end
end
GC.under_stress {...}
:
module GC
def self.under_stress
flag_old = stress
self.stress = true
yield
ensure
self.stress = flag_old
end
end
GC.stress(flag = true) {...}
:
module GC
def stress flag = true
if block_given?
flag_old = Primitive.gc_stress_get
begin
GC.stress = flag
ensure
GC.stress = flag_old
end
else
Primitive.gc_stress_get
end
end
end
Note:
- Disadvantage is,
GC.stress
is a getter method andGC.stress do end
is setter method. It can be confusing. - @nobu (Nobuyoshi Nakada) also pointed out that the block is just ignored on the older Ruby versions.
Source of implementation and some discussions: https://github.com/ruby/ruby/pull/4793
Background:
I'm maintaining some default gems. They have copy of EnvUtil
but I don't want to have it for maintainability. If Ruby provides this feature by default, we can use it instead of copying EnvUtil
. I know that I need to implement/copy the feature in each default gem until Ruby 3.0 reaches EOL. But we don't have the feature now, I need to copy EnvUtil
forever.