Ruby on rails 临时文件和垃圾收集

Ruby on rails 临时文件和垃圾收集,ruby-on-rails,ruby,garbage-collection,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: 垃圾回收时可能自动触发

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

  open(source) { |s| content = s.read }
  rss = RSS::Parser.parse(content, false)
这导致临时文件填满了(稀缺的)磁盘空间

我在某种程度上研究了这个问题,结果发现在堆栈的某个地方发生了这种情况:

io = Tempfile.new('open-uri')
但看起来这个Tempfile实例从未被显式关闭。它有一个

def _close  # :nodoc:
垃圾回收时可能自动触发的方法


了解发生了什么或如何清理临时文件方面的任何帮助都会非常有用

看起来像是
\u close
关闭文件,然后等待垃圾回收取消链接(删除)文件。理论上,您可以通过调用
Tempfile
close来强制立即取消链接close
,或者调用
close(true)
(内部调用
close!

编辑:但问题出在OpenURI中,它不在您的控制范围之内——这并不能保证在其自身之后进行清理:它只是假设垃圾收集器将在适当的时候完成所有
Tempfile
s


在这种情况下,您别无选择,只能自己使用
ObjectSpace.garbage\u-collect
()调用垃圾收集器。这将导致删除所有临时文件。

肯定不是错误,而是处理IO时出错。如果@size小于10240字节,则Buffer.io为StringIO;如果@size大于10240字节,则为Tempfile。OpenURI.open_uri()中的sure子句正在调用close(),但因为它可能是一个没有close的StringIO对象!()方法,它不能只调用close!()

我认为,解决办法可能是:

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

--或--

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

当然,如果不使用块来处理IO,这两种方法都不能解决问题,但我认为在这种情况下,您可以自己进行检查,因为open()返回IO对象,而不是Buffer对象


lib是一大块凌乱的代码,imho,因此它可以使用一个工作来清理它。我想我可能会那样做,只是为了好玩。^

如果您真的想强制
OpenURI
不使用tempfile,可以使用
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> 

那么,谁叫你close?如果没有猴子补丁,我想我无法访问那个临时文件。我现在看到问题了。我在答案中添加了更多的信息,希望对你有用。谢谢!我无法想象显式调用GC会解决这个问题。在我的测试中,让tempfile不被清理的唯一方法是中断程序。所以我不知道会发生什么。我认为这是
开放uri
中的一个错误(可能不是错误本身,但肯定是错误行为),它没有正确清理临时文件。也就是说,它传递缓冲区的次数太多,以至于很难找到关闭临时文件的位置。我确实相信很多重构可以解决
openuri
中的问题,但这需要等待下一次:-)SynTruth,我明白了这个想法,但在duck类型语言中,您不检查类。您可以检查它是否响应方法:)。无论如何,我现在离这个问题太远了,我不知道你是否解决了它。但是,如果你有,请报告,只是出于好奇。
class Buffer
  [...]
  StringMax = 10240
  def <<(str)
    [...]
    if [...] StringMax < @size
      require 'tempfile'