Project

General

Profile

Bug #19460

Updated by luke-gru (Luke Gruber) about 1 year ago

I'm working on something where I need to remove a class and release all memory related to that class. 
 I've stumbled upon a limitation where in some instances I cannot get the class to be GC'd. The problem 
 (I think) is that inline method caches cache the class, and even if the class would otherwise be gone, it stays. 
 For example: 

 ```ruby 
 class A 
   def do_something 
     self.call_other # inline cache caches class A, so now A is marked every time cache is marked 
   end 
   def call_other 
   end 
 end 
 a = A.send(:new) A.new 
 a.send(:do_something) # don't make normal call, use send so no inline cache used here 
 a_id = A.object_id 
 a = nil 
 Object.send(:remove_const, :A) 

 # A should be able to be released now. 

 10.times { GC.start } 
 a_ref = ObjectSpace._id2ref(a_id) rescue nil 
 puts "a_ref: #{a_ref.class}" 

 # we get NilClass, it is released 
 ```ruby 

 However: using `A.new` above, it can't be GC'd. 
 If there is an initialize method (even empty) it can't be GC'd. 
 If there's a method call inside the class One solution to another instance method on self ex: `self.do_something`, it can't this would be GC'd. 

 I'm not sure exactly what is going on but it looks like an if inline cache marking issue. Maybe caches are getting marked, even inside methods where methods, only mark them when the method itself doesn't get is marked. 
 I'm guessing they're marked independently right now.

Back