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