【问题标题】:Fog gem leaking memory雾宝石泄漏内存
【发布时间】:2014-09-18 21:40:20
【问题描述】:

我编写了一个脚本,通过我的 Rackspace 云文件容器递归下载并检索每个文件的副本,因此我有一个本地备份,以防 Rackspace 被流星和/或hindenbugs 击中。

但是,我的脚本在下载文件时显然会以线性比例泄漏内存。

基本上我有一个看起来像这样的方法:

def download_file(fog_file, destination_path)
  data = fog_file.body
  File.open(destination_path, 'w') { |f| f.write(data) }
end

我了解由于 Fog 的性质,我无法避免将整个文件加载到内存中,但我想 Ruby 会在每次 download_file 调用后释放内存(或有能力释放内存)。毕竟,data 变量超出了范围。

不幸的是,当我查看我的系统监控时,内存使用量一直以线性速度增加,直到它消耗了我所有的可用内存,此时脚本崩溃。

我在这里做错了什么?

我在 Ubuntu 上使用 Ruby 2.1.2。

【问题讨论】:

  • 不确定为什么要泄漏(您是否保留了雾文件的引用?)但您可以流式下载雾文件(例如,请参阅kylev.com/2013/05/14/foggy-sponges-and-kittens
  • Ruby 在关于 File.open 的 do/end 块之后内置了垃圾收集。尝试显式关闭文件,看看是否有帮助。

标签: ruby fog


【解决方案1】:

您可以通过两种方式避免将整个文件加载到内存中。

首先,您可以检索 100kb(或更少)夹头的文件:

service = Fog::Storage.new({ provider: 'Rackspace', 
                             # ... auth config
                             connection_options: {chunk_size: 102_400} # 100 KB in bytes                        
})

directory = service.directories.get "dir"

File.open((destination_path, 'w') do | f |
  directory.files.get("my_file_on_cloud.png") do | data, remaining, content_length |
    f.syswrite data
  end
end

其次,您可以使用雾检索文件 url,然后使用 OpenUri 下载并保存文件:

require 'open-uri'

file = open(file.public_url).read
File.open(destination_path, 'w') { |f| f.write(file) }

第一种方法直接写入目标文件,第二种方法创建一个Tempfile 实例(在文件系统上创建一个临时文件)。两个都试试。

【讨论】:

  • 这是一个老问题,我实际上用第一种方法解决了这个问题。请记住,chunk_size(至少对于 Rackspace)占用字节而不是兆字节,因此 0.100 可能不起作用。我使用connection_options: {chunk_size: 20_971_520} 一次获得 20 兆字节。它解决了泄漏问题。
猜你喜欢
  • 2017-01-03
  • 1970-01-01
  • 1970-01-01
  • 2012-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多