英文:
Question about out-of-scope FFI MemoryPointer that is returned from a method
问题
在这种情况下,内部在foo
和bar
方法中创建的MemoryPointer
何时被垃圾回收呢?它是在foo
和bar
方法中MemoryPointer
变量离开作用域时,还是在testing
方法中a
或b
这些本地变量(它们引用了从foo
/bar
方法返回的MemoryPointer
)离开作用域时?
在这种情况下,MemoryPointer
对象将在以下情况被垃圾回收:
-
对于
foo
方法:MemoryPointer
对象将在foo
方法中的result
变量离开作用域时被垃圾回收。 -
对于
bar
方法:MemoryPointer
对象将在bar
方法中的value
变量和simple_struct
对象离开作用域时被垃圾回收。 -
对于
testing
方法:MemoryPointer
对象将在testing
方法中的变量a
和b
离开作用域时被垃圾回收。这是因为在testing
方法中,变量a
和b
分别引用了foo
和bar
方法返回的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 '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
A pointer is only garbage collected when the struct is garbage-collected, as is the case with a hash.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论