キャッシュディレクトリにrmagickで画像を作成する必要がある場合があります。
次に、ビューでそれらを失うことなく、それらをすばやく削除するために、私はRuby Image-Classのインスタンスが破壊されるかガベージコレクションに入る間に画像ファイルを削除します。
デストラクタにコードを提供するには、どのClassMethodを上書きする必要がありますか?
ObjectSpace.define_finalizer
画像ファイルを作成すると、ゴミの人が収集するときに呼び出されます。自分のprocでオブジェクト自体を参照しないように注意してください。そうしないと、ガベージマンによってオブジェクトが収集されません。 (生きていて蹴っているものを拾わないでください)
class MyObject
def generate_image
image = ImageMagick.do_some_magick
ObjectSpace.define_finalizer(self, proc { image.self_destruct! })
end
end
@edgerunnerのソリューションはほぼ機能しました。基本的に、define_finalizer
呼び出しの代わりにクロージャーを作成することはできません。これは、現在のself
のバインディングをキャプチャするためです。 Ruby 1.8では、proc
にバインドされているメソッドから変換されたself
オブジェクトを(to_proc
を使用して)変換することはできないようです。これを機能させるには、ファイナライザを定義しているオブジェクトをキャプチャしない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
GCの癖は読みやすいですが、既存の言語構文に従ってリソースを適切に割り当て解除しないのはなぜですか?
はっきりさせておきます。
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が指摘するように、これは誤りのようです。ただし、それらが頻繁に使用されることはありません。適切に構築されたデストラクタ割り当てベースの言語では必須ですが、ガベージコレクションされたものでは、オプションになります。
あなたの問題に対する非常に簡単な解決策があります。 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