我需要偶尔在缓存目录中使用RMagick创建图像。
为了快速摆脱它们,同时不影响视图,我想在我的Ruby Image-Class实例被破坏或进入Garbage Collection时删除图像文件。
我需要重写哪个类方法来向析构函数注入代码?
我需要偶尔在缓存目录中使用RMagick创建图像。
为了快速摆脱它们,同时不影响视图,我想在我的Ruby Image-Class实例被破坏或进入Garbage Collection时删除图像文件。
我需要重写哪个类方法来向析构函数注入代码?
@edgerunner的解决方案几乎可以使用。基本上,您不能创建一个闭包来代替define_finalizer
调用,因为它会捕获当前self
的绑定。在Ruby 1.8中,似乎您也不能使用从绑定到self
的方法转换(使用to_proc
)的任何proc
对象。要使其起作用,您需要一个不会捕获正在定义finalizer的对象的proc
对象。
class A
FINALIZER = lambda { |object_id| p "finalizing %d" % object_id }
def initialize
ObjectSpace.define_finalizer(self, self.class.method(:finalize)) # Works in both 1.9.3 and 1.8
#ObjectSpace.define_finalizer(self, FINALIZER) # Works in both
#ObjectSpace.define_finalizer(self, method(:finalize)) # Works in 1.9.3
end
def self.finalize(object_id)
p "finalizing %d" % object_id
end
def finalize(object_id)
p "finalizing %d" % object_id
end
end
a = A.new
a = nil
GC.start
ObjectSpace.define_finalizer
,垃圾回收器在回收时会自动调用该方法。只需注意不要在处理程序中引用对象本身,否则它将不会被垃圾回收器回收。(不会回收仍然存在的对象)class MyObject
def generate_image
image = ImageMagick.do_some_magick
ObjectSpace.define_finalizer(self, proc { image.self_destruct! })
end
end
self
保持隐式引用——在这种情况下,即与附加终结器的对象相同,因此终结器将防止对象被回收。 - ChuckGC怪癖很有趣,但为什么不根据已经存在的语言语法正确地释放资源呢?
让我澄清一下。
class ImageDoer
def do_thing(&block)
image= ImageMagick.open_the_image # creates resource
begin
yield image # yield execution to block
rescue
# handle exception
ensure
image.destruct_sequence # definitely deallocates resource
end
end
end
doer= ImageDoer.new
doer.do_thing do |image|
do_stuff_with_image # destruct sequence called if this throws
end # destruct_sequence called if execution reaches this point
代码块执行完毕后图像将被销毁。只需开始一个块,在其中进行所有的图像处理,然后让图像自行销毁。这类似于以下C++示例:
struct Image
{
Image(){ /* open the image */ }
void do_thing(){ /* do stuff with image */ }
~Image(){ /* destruct sequence */ }
};
int main()
{
Image img;
img.do_thing(); // if do_thing throws, img goes out of scope and ~Image() is called
} // special function ~Image() called automatically here
Ruby提供了ObjectSpace.define_finalizer
函数来设置对象的终结器,但并不鼓励使用它,而且它的功能比较有限(例如,终结器不能引用被设置终结器的对象,否则该对象将无法进行垃圾回收)。
在Ruby中,实际上并不存在析构函数。
你可以简单地清除不再打开的任何文件,或者使用TempFile类来代替你完成这个操作。
更新:
我之前声称PHP、Perl和Python没有析构函数,但是igorw指出这是错误的。虽然我很少见到它们被使用。在任何基于分配的语言中,一个正确构造的析构函数是必不可少的,但在垃圾回收的语言中,它最终变成了可选项。
find $DIRECTORY -type f -mtime +$RETAIN_PERIOD -exec rm {} \;
,其中 $DIRECTORY
是要处理的目录,$RETAIN_PERIOD
是你想要保留它们的天数。你也可以在 Ruby 中使用 File::Stat#mtime
和一些粘合剂来完成这个任务。 - tadmanEND
和DESTROY
方法,但我从来没有见过普通人使用它们。 - tadman针对您的问题,有一个非常简单的解决方案。Ruby的设计鼓励您以明确和清晰的方式执行所有操作。在构造函数/析构函数中不需要进行任何神奇的操作。是的,构造函数是必需的,作为分配对象初始状态的便捷方式,但不是用于“神奇”操作的。让我通过可能的解决方案来说明这种方法。 目标是保持图像对象可用,但清除图像缓存文件。
# you are welcome to keep an in memory copy of the image
# GC will take care of it.
class MyImage
RawPNG data
end
# this is a worker that does operations on the file in cache directory.
# It knows presizely when the file can be removed (generate_image_final)
# no need to wait for destructor ;)
class MyImageGenerator
MyImage @img
def generate_image_step1
@image_file = ImageLib.create_file
end
def generate_image_step2
ImageLib.draw @image_file
end
def generate_image_final
@img=ImageLib.load_image @image_file
delete_that_file @image_file
end
def getImage
# optional check image was generated
return @img
end
end