Ruby FFI中返回的MemoryPointer何时会被垃圾回收?
示例代码
class SimpleStruct < FFI::Struct layout :value, :pointer end class Test1 def self.foo(s) result = FFI::MemoryPointer.from_string(s) result end def self.bar(s) simple_struct = SimpleStruct.new value = FFI::MemoryPointer.from_string(s) simple_struct[:value] = value simple_struct end end class Test2 def self.testing a = Test1.foo('test') b = Test1.bar('test') puts a.read_string, b[:value].read_string end end
问题背景
FFI官方维基提到:When a MemoryPointer goes out of scope, the memory is freed up as part of the garbage collection process(当MemoryPointer超出作用域时,其占用内存会作为垃圾回收的一部分被释放)。针对上述代码,疑问是:Test1的foo、bar方法内创建的MemoryPointer,到底是在方法内的变量超出作用域时被回收,还是在Test2#testing方法里的a、b变量超出作用域时才被回收?
解答
首先要明确:Ruby的垃圾回收机制是基于对象可达性的,而非单纯的词法作用域。FFI的MemoryPointer本质是Ruby对象,完全遵循Ruby的GC规则,维基里的“out of scope”实际指的是该MemoryPointer对象不再被任何Ruby对象引用的状态。
分两种场景说明:
foo方法返回的MemoryPointer
foo方法内创建的result(MemoryPointer对象)被作为返回值赋值给了testing方法里的a变量。此时,尽管foo方法执行完毕后,内部的result变量已经出了词法作用域,但它指向的MemoryPointer对象还被a引用着,所以不会被GC回收。只有当a变量超出testing方法的作用域,且没有其他任何Ruby对象再引用这个MemoryPointer时,GC才会回收该对象,同时释放对应的内存。bar方法内创建的MemoryPointer
bar方法内创建的value(MemoryPointer对象)被赋值给了simple_struct的:value字段,随后这个结构体被返回给testing方法的b变量。只要b变量还存在(或者结构体本身还有其他引用),这个MemoryPointer就会被结构体持有引用,因此不会被回收。只有当b超出作用域,且没有其他引用指向该结构体,同时这个MemoryPointer也没有其他额外引用时,GC才会回收它并释放内存。
简单总结:方法内的MemoryPointer变量出作用域并不会直接触发回收,只有当对应的MemoryPointer对象失去所有可达引用(比如外部的a、b也不再引用它)时,才会被Ruby GC处理,进而释放内存。
内容的提问来源于stack exchange,提问作者null

