在 Ruby 中分配内存失败(No MemoryError)?

Posted

技术标签:

【中文标题】在 Ruby 中分配内存失败(No MemoryError)?【英文标题】:Failed to allocate memory (No MemoryError) in Ruby? 【发布时间】:2014-06-24 14:31:14 【问题描述】:

我编写了一个简单的脚本,它应该读取整个目录,然后通过去掉 html 标签将 HTML 数据解析为普通脚本,然后将其写入一个文件。

我有 8GB 内存和大量可用的虚拟内存。当我这样做时,我有超过 5GB 的可用 RAM。目录中最大的文件为 3.8 GB。

脚本是

file_count = 1
File.open("allscraped.txt", 'w') do |out1|
    for file_name in Dir["allParts/*.dat"] do
        puts "#file_name#:#file_count"
        file_count +=1
        File.open(file_name, "r") do |file|
            source = ""
            tmp_src = ""
            counter = 0
            file.each_line do |line|
                scraped_content = line.gsub(/<.*?\/?>/, '')
                tmp_src << scraped_content
                if (counter % 10000) == 0
                    tmp_src = tmp_src.gsub( /\s2,/, "\n" )
                    source << tmp_src
                    tmp_src = ""
                    counter = 0
                end
                counter += 1
            end
            source << tmp_src.gsub( /\s2,/, "\n" )
            out1.write(source)
            break
        end
    end
end

完整的错误代码是:

realscraper.rb:33:in `block (4 levels) in <main>': failed to allocate memory (No
MemoryError)
        from realscraper.rb:27:in `each_line'
        from realscraper.rb:27:in `block (3 levels) in <main>'
        from realscraper.rb:23:in `open'
        from realscraper.rb:23:in `block (2 levels) in <main>'
        from realscraper.rb:13:in `each'
        from realscraper.rb:13:in `block in <main>'
        from realscraper.rb:12:in `open'
        from realscraper.rb:12:in `<main>'

其中第 27 行是 file.each_line do |line|,第 33 行是 source &lt;&lt; tmp_src。失败的文件是最大的文件 (3.8 GB)。这里有什么问题?即使我有足够的内存,为什么我会收到此错误?还有怎么解决?

【问题讨论】:

失败的文件有多大?它是否有换行符? 首先添加日志以查看它是在特定文件上还是在特定时间后失败。如果它总是在同一个文件中失败,请尝试在只有该文件的文件夹上运行它。它将为您提供有价值的信息。 @Patru,感谢您的提醒,我更新了我的答案。这是最大的一个。 @Martin,正如我所说的它是最高的,我自己尝试了一下,得到了同样的错误。 ++counter 不是有效的 Ruby(至少它不会像您认为的那样做)。 【参考方案1】:

问题出在这两行:

source << tmp_src
source << tmp_src.gsub( /\s2,/, "\n" )

当您读取一个大文件时,您会在内存中慢慢增长一个非常大的字符串。

最简单的解决方案是根本不使用这个临时的source 字符串,而是将结果直接写入文件。只需将这两行替换为:

# source << tmp_src
out1.write(tmp_src) 

# source << tmp_src.gsub( /\s2,/, "\n" )
out1.write(tmp_src.gsub( /\s2,/, "\n" ))                     

这样您就不会在内存中创建任何大的临时字符串,并且它应该可以更好(更快)地工作。

【讨论】:

以上是关于在 Ruby 中分配内存失败(No MemoryError)?的主要内容,如果未能解决你的问题,请参考以下文章

ruby 从最后一个表中分配表

如果您在进程崩溃后在进程中分配内存会发生啥?

实例变量未在内存中分配

在linux中分配物理内存缓冲区

printf() 是不是在 C 中分配内存?

如何使用 mmap 在堆中分配内存?