Bug #19041
closedWeakref is still alive after major garbage collection
Description
I am able to get into an infinite loop waiting for garbage collection to take a WeakRef.
Reproduction Process¶
The following script prints a "0", then a "1", and then hangs forever. I expect it to keep printing numbers.
require "weakref"
iterations = 0
loop do
print "\r#{iterations}"
obj = WeakRef.new(Object.new)
GC.start while obj.weakref_alive?
iterations += 1
end
Ruby Version¶
I have tested this on Ruby 3.1.2, 3.1.0, 3.0.4, 3.0.0, 2.7.6, and 2.7.0 on macOS. All exhibit this behavior.
Further Investigation¶
Sleeping¶
Sleeping before the garbage collection allows the loop to continue. The below exhibits the expected behavior:
require "weakref"
iterations = 0
loop do
print "\r#{iterations}"
obj = WeakRef.new(Object.new)
(sleep(0.5); GC.start) while obj.weakref_alive?
iterations += 1
end
However, sleeping after the garbage collection still shows the buggy behavior (loop hangs):
require "weakref"
iterations = 0
loop do
print "\r#{iterations}"
obj = WeakRef.new(Object.new)
(GC.start; sleep(0.5)) while obj.weakref_alive?
iterations += 1
end
Running Garbage Collection Multiple Times¶
Explicitly running garbage collection multiple times allows the loop to continue. This has the expected behavior, more numbers continue to be printed:
require "weakref"
iterations = 0
loop do
print "\r#{iterations}"
obj = WeakRef.new(Object.new)
while obj.weakref_alive?
GC.start
GC.start
GC.start
end
iterations += 1
end
However, with certain rubies, running those garbage collection calls in a times
block prevents even a single iteration from completing. The following prints only "0" with ruby 3.0.4 on macOS, ruby 2.7.6 on macOS, and ruby 3.1.2 on linux (ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-linux]
on a virtual machine). It shows the expected behavior on ruby 3.1.2 on macOS.
require "weakref"
iterations = 0
loop do
print "\r#{iterations}"
obj = WeakRef.new(Object.new)
3.times { GC.start } while obj.weakref_alive?
iterations += 1
end
Files