From: "tenderlovemaking (Aaron Patterson)" Date: 2022-10-17T17:31:53+00:00 Subject: [ruby-core:110369] [Ruby master Bug#19041] Weakref is still alive after major garbage collection Issue #19041 has been updated by tenderlovemaking (Aaron Patterson). parker (Parker Finch) wrote in #note-6: > I'm still curious _why_ calling `#weakref_alive?` on the `WeakRef` seems to put the underlying `Object` (that the `WeakRef` delegates to) in a register or on the stack. But the fact that this is happening so close to the actual machine makes it seem like it would be tricky to figure out. That method may not be putting the object in a register. Something else may have put it in a register or in the stack, and it just happens that no other machine code has overwritten the register or stack memory. If you dump the heap (`ObjectSpace.dump_all`), you'll probably see one of the roots (probably VM?) pointing at the object. Unfortunately the heap dump won't tell you _how_ it found the reference, just that the reference exists. You could find whether it's a register or stack memory by adding some debugging code to the GC or by tracing the machine code via lldb. It might be nice if `ObjectSpace.dump_all` could indicate whether the reference came from the stack or machine registers as I've also tried to figure that out. But it is work. ���� ---------------------------------------- Bug #19041: Weakref is still alive after major garbage collection https://bugs.ruby-lang.org/issues/19041#change-99663 * Author: parker (Parker Finch) * Status: Closed * 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: