关于从方法返回的超出范围的 FFI MemoryPointer 的问题

huangapple go评论71阅读模式
英文:

Question about out-of-scope FFI MemoryPointer that is returned from a method

问题

在这种情况下,内部在foobar方法中创建的MemoryPointer何时被垃圾回收呢?它是在foobar方法中MemoryPointer变量离开作用域时,还是在testing方法中ab这些本地变量(它们引用了从foo/bar方法返回的MemoryPointer)离开作用域时?

在这种情况下,MemoryPointer对象将在以下情况被垃圾回收:

  1. 对于foo方法:MemoryPointer对象将在foo方法中的result变量离开作用域时被垃圾回收。

  2. 对于bar方法:MemoryPointer对象将在bar方法中的value变量和simple_struct对象离开作用域时被垃圾回收。

  3. 对于testing方法:MemoryPointer对象将在testing方法中的变量ab离开作用域时被垃圾回收。这是因为在testing方法中,变量ab分别引用了foobar方法返回的MemoryPointer对象,当这些变量离开作用域时,没有更多的引用指向这些对象,它们就会变得可垃圾回收。

总之,在Ruby中,当没有引用指向一个对象时,它就会变得可垃圾回收。所以,在这种情况下,MemoryPointer对象将在最后一次引用它的变量离开作用域时被垃圾回收。

英文:

Let's say I have the following ruby code that uses FFI library:

  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

The FFI wiki mentions When a MemoryPointer goes out of scope, the memory is freed up as part of the garbage collection process. In the Test1 class above, foo method returns a MemoryPointer and bar method returns an FFI struct that holds MemoryPointer. The testing method in Test2 class calls these methods and stores the returned values in variable a and b respectively.

My question is when the MemoryPointer created inside foo and bar method will be garbage collected in this case? Is it when the MemoryPointer variable goes out of scope in foo and bar methods or when the local variable a or b (that references the MemoryPointer returned from the foo/bar methods) goes out of scope in testing method?

答案1

得分: 1

我相信 FFI::Struct#[]= 处理了这个问题。我没有在源代码中检查它,但我在您的代码中添加了一些检查,看起来是这样的。

require 'ffi'

class SimpleStruct < FFI::Struct
  layout :value, :pointer
end

class Test1
  def self.foo(s)
    puts "foo is called"
    result = FFI::MemoryPointer.from_string(s)
    ObjectSpace.define_finalizer(result, proc { puts "foo result is garbage collected" })
    result
  end

  def self.bar(s)
    puts "bar is called"
    simple_struct = SimpleStruct.new
    ObjectSpace.define_finalizer(s, proc { puts "bar result is garbage collected" })
    value = FFI::MemoryPointer.from_string(s)
    ObjectSpace.define_finalizer(s, proc { puts "bar result[:value] is garbage collected" })
    simple_struct[:value] = value

    simple_struct
  end

  def self.baz(s)
    puts "baz is called"
    simple_struct = {}
    ObjectSpace.define_finalizer(s, proc { puts "baz result is garbage collected" })
    value = FFI::MemoryPointer.from_string(s)
    ObjectSpace.define_finalizer(s, proc { puts "baz result[:value] is garbage collected" })
    simple_struct[:value] = value

    simple_struct
  end
end

class Test2
  def self.testing
    puts "testing is started"
    a = Test1.foo('foo')
    b = Test1.bar('bar')
    c = Test1.baz('baz')

    puts a.read_string, b[:value].read_string, c[:value].read_string
    puts "testing is finished"
  end
end

GC.stress

Test2.testing

# testing is started
# foo is called
# bar is called
# baz is called
# foo
# bar
# baz
# testing is finished
# baz result is garbage collected
# baz result[:value] is garbage collected
# bar result is garbage collected
# bar result[:value] is garbage collected
# foo result is garbage collected

只有当结构被垃圾回收时,指针才会被垃圾回收,就像哈希表一样。

英文:

I believe FFI::Struct#[]= takes care of this. I didn't check it in the sources, but I've added some checks into your code and it looks so.

require &#39;ffi&#39;
class SimpleStruct &lt; FFI::Struct
layout :value, :pointer
end
class Test1
def self.foo(s)
puts &quot;foo is called&quot;
result = FFI::MemoryPointer.from_string(s)
ObjectSpace.define_finalizer(result, proc { puts &quot;foo result is garbage collected&quot; })
result
end
def self.bar(s)
puts &quot;bar is called&quot;
simple_struct = SimpleStruct.new
ObjectSpace.define_finalizer(s, proc { puts &quot;bar result is garbage collected&quot; })
value = FFI::MemoryPointer.from_string(s)
ObjectSpace.define_finalizer(s, proc { puts &quot;bar result[:value] is garbage collected&quot; })
simple_struct[:value] = value
simple_struct
end
def self.baz(s)
puts &quot;baz is called&quot;
simple_struct = {}
ObjectSpace.define_finalizer(s, proc { puts &quot;baz result is garbage collected&quot; })
value = FFI::MemoryPointer.from_string(s)
ObjectSpace.define_finalizer(s, proc { puts &quot;baz result[:value] is garbage collected&quot; })
simple_struct[:value] = value
simple_struct
end
end
class Test2
def self.testing
puts &quot;testing is started&quot;
a = Test1.foo(&#39;foo&#39;)
b = Test1.bar(&#39;bar&#39;)
c = Test1.baz(&#39;baz&#39;)
puts a.read_string, b[:value].read_string, c[:value].read_string
puts &quot;testing is finished&quot;
end
end
GC.stress
Test2.testing
# testing is started
# foo is called
# bar is called
# baz is called
# foo
# bar
# baz
# testing is finished
# baz result is garbage collected
# baz result[:value] is garbage collected
# bar result is garbage collected
# bar result[:value] is garbage collected
# foo result is garbage collected

A pointer is only garbage collected when the struct is garbage-collected, as is the case with a hash.

huangapple
  • 本文由 发表于 2023年6月15日 19:33:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/76482044.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定