【发布时间】:2013-12-21 13:17:00
【问题描述】:
我在我的 Rails 代码中发现了内存泄漏 - 也就是说,我发现了 what 代码泄漏,但没有发现 为什么 它泄漏。我已将其简化为不需要 Rails 的测试用例:
require 'csspool'
require 'ruby-mass'
def report
puts 'Memory ' + `ps ax -o pid,rss | grep -E "^[[:space:]]*#{$$}"`.strip.split.map(&:to_i)[1].to_s + 'KB'
Mass.print
end
report
# note I do not store the return value here
CSSPool::CSS::Document.parse(File.new('/home/jason/big.css'))
ObjectSpace.garbage_collect
sleep 1
report
ruby-mass 据说可以让我看到内存中的所有对象。 CSSPool 是一个基于 racc 的 CSS 解析器。 /home/jason/big.css 是a 1.5MB CSS file。
这个输出:
Memory 9264KB
==================================================
Objects within [] namespace
==================================================
String: 7261
RubyVM::InstructionSequence: 1151
Array: 562
Class: 313
Regexp: 181
Proc: 111
Encoding: 99
Gem::StubSpecification: 66
Gem::StubSpecification::StubLine: 60
Gem::Version: 60
Module: 31
Hash: 29
Gem::Requirement: 25
RubyVM::Env: 11
Gem::Specification: 8
Float: 7
Gem::Dependency: 7
Range: 4
Bignum: 3
IO: 3
Mutex: 3
Time: 3
Object: 2
ARGF.class: 1
Binding: 1
Complex: 1
Data: 1
Gem::PathSupport: 1
IOError: 1
MatchData: 1
Monitor: 1
NoMemoryError: 1
Process::Status: 1
Random: 1
RubyVM: 1
SystemStackError: 1
Thread: 1
ThreadGroup: 1
fatal: 1
==================================================
Memory 258860KB
==================================================
Objects within [] namespace
==================================================
String: 7456
RubyVM::InstructionSequence: 1151
Array: 564
Class: 313
Regexp: 181
Proc: 113
Encoding: 99
Gem::StubSpecification: 66
Gem::StubSpecification::StubLine: 60
Gem::Version: 60
Module: 31
Hash: 30
Gem::Requirement: 25
RubyVM::Env: 13
Gem::Specification: 8
Float: 7
Gem::Dependency: 7
Range: 4
Bignum: 3
IO: 3
Mutex: 3
Time: 3
Object: 2
ARGF.class: 1
Binding: 1
Complex: 1
Data: 1
Gem::PathSupport: 1
IOError: 1
MatchData: 1
Monitor: 1
NoMemoryError: 1
Process::Status: 1
Random: 1
RubyVM: 1
SystemStackError: 1
Thread: 1
ThreadGroup: 1
fatal: 1
==================================================
您可以看到内存在方式上升。一些计数器上升,但不存在特定于 CSSPool 的对象。我使用 ruby-mass 的“索引”方法来检查具有如下引用的对象:
Mass.index.each do |k,v|
v.each do |id|
refs = Mass.references(Mass[id])
puts refs if !refs.empty?
end
end
但同样,这并没有给我任何与 CSSPool 相关的信息,只是 gem 信息等。
我也试过输出“GC.stat”...
puts GC.stat
CSSPool::CSS::Document.parse(File.new('/home/jason/big.css'))
ObjectSpace.garbage_collect
sleep 1
puts GC.stat
结果:
{:count=>4, :heap_used=>126, :heap_length=>138, :heap_increment=>12, :heap_live_num=>50924, :heap_free_num=>24595, :heap_final_num=>0, :total_allocated_object=>86030, :total_freed_object=>35106}
{:count=>16, :heap_used=>6039, :heap_length=>12933, :heap_increment=>3841, :heap_live_num=>13369, :heap_free_num=>2443302, :heap_final_num=>0, :total_allocated_object=>3771675, :total_freed_object=>3758306}
据我了解,如果一个对象没有被引用并且发生垃圾回收,那么应该从内存中清除该对象。但这似乎不是这里发生的事情。
我还阅读了有关 C 级内存泄漏的信息,并且由于 CSSPool 使用使用 C 代码的 Racc,我认为这是一种可能性。我已经通过 Valgrind 运行了我的代码:
valgrind --partial-loads-ok=yes --undef-value-errors=no --leak-check=full --fullpath-after= ruby leak.rb 2> valgrind.txt
结果为@987654325@。我不确定这是否证实了 C 级泄漏,因为我还读到 Ruby 使用 Valgrind 不理解的内存进行操作。
使用的版本:
- Ruby 2.0.0-p247(这是我的 Rails 应用运行的)
- Ruby 1.9.3-p392-ref(用于使用 ruby-mass 进行测试)
- 红宝石质量 0.1.3
- CSSPool 4.0.0 来自here
- CentOS 6.4 和 Ubuntu 13.10
【问题讨论】:
-
我使用 1.9.3.x 在我的机器上重现了同样的问题。你用的是什么版本?
-
我已在问题中添加了版本信息。
标签: ruby memory-leaks valgrind