From: "byroot (Jean Boussier)" Date: 2022-10-06T19:32:16+00:00 Subject: [ruby-core:110219] [Ruby master Bug#19041] Weakref is still alive after major garbage collection Issue #19041 has been updated by byroot (Jean Boussier). I don't think this is a bug per say. The Ruby GC is conservative. That means it goes over the whole stack in search for potential references to objects, and mark them. As a result, it can happen that an object ref stays in an unused saved register and prevent an object from being merged. ---------------------------------------- Bug #19041: Weakref is still alive after major garbage collection https://bugs.ruby-lang.org/issues/19041#change-99503 * Author: parker (Parker Finch) * Status: Open * Priority: Normal * ruby -v: ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [x86_64-darwin21] * Backport: 2.7: UNKNOWN, 3.0: UNKNOWN, 3.1: UNKNOWN ---------------------------------------- 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 ``` -- https://bugs.ruby-lang.org/ Unsubscribe: