Tempfile和垃圾收集

时间:2009-09-03 22:18:35

标签: ruby-on-rails ruby garbage-collection

我在Rails控制器中有这个命令

  open(source) { |s| content = s.read }
  rss = RSS::Parser.parse(content, false)

导致临时文件填满(稀缺)磁盘空间。

我已经在某种程度上检查了这个问题,结果发生在堆栈的某个地方:

io = Tempfile.new('open-uri')

但看起来这个Tempfile实例永远不会被显式关闭。它有一个

def _close  # :nodoc:

垃圾收集时可能自动触发的方法?

任何有助于了解正在发生的事情或如何清理临时文件的帮助确实会有所帮助。

3 个答案:

答案 0 :(得分:4)

如果你真的想强制open-uri不使用临时文件,你可以搞乱OpenURI::Buffer::StringMax常量:

> require 'open-uri'
=> true 
> OpenURI::Buffer::StringMax
=> 10240 
> open("http://www.yahoo.com")
=> #<File:/tmp/open-uri20110111-16395-8vco29-0> 
> OpenURI::Buffer::StringMax = 1_000_000_000_000
(irb):10: warning: already initialized constant StringMax
=> 1000000000000 
> open("http://www.yahoo.com")
=> #<StringIO:0x6f5b1c> 

这是因为open-uri.rb的这个代码段:

class Buffer
  [...]
  StringMax = 10240
  def <<(str)
    [...]
    if [...] StringMax < @size
      require 'tempfile'

答案 1 :(得分:2)

看起来_close关闭文件,然后等待垃圾收集以取消链接(删除)文件。从理论上讲,您可以通过调用Tempfile的{​​{1}}方法而不是close!来强制取消链接,或者调用close(内部调用close(true))。

编辑:但是问题出在open-uri,这不在你手中 - 并且没有任何承诺清理它自己:它只是假设垃圾收集器将完成所有{ {1}}适时。{/ p>

在这种情况下,您别无选择,只能使用close!see here)自行调用垃圾收集器。这应该会导致删除所有临时文件。

答案 2 :(得分:2)

绝对不是错误,但处理IO的错误错误。如果@size小于10240字节,则Buffer.io为StringIO,如果超过该数量,则为Tempfile。 OpenURI.open_uri()中的ensure子句调用close(),但因为它可能是一个StringIO对象,它没有close!()方法,所以它不能只调用close!()。

我认为,修正案可能是其中之一:

ensure子句检查类并调用StringIO.close或Tempfile.close!根据需要。

- 或 -

Buffer类需要一个处理类检查的终结器并调用正确的方法。

当然,如果您不使用块来处理IO,那么这些都没有解决它,但我想在这种情况下,您可以自己进行检查,因为open()返回IO对象,而不是Buffer对象

lib是一大堆凌乱的代码,imho,所以它可以使用修复来清理它。我想我可能会这样做,只是为了好玩。 ^。^