小记rails内存泄漏

阅读更多
刚刚上了一个rails(ruby-1.8.5-p12+rails1.2.3+lighttpd)项目,却出现了严重的内存泄漏
上线不到几个小时,内存就好到1G, 一般情况下每个fcgi进程也就20-30+m。
实在不知道怎么弄,网上看看说fcig可能会有内存泄漏,于是换成mongrel1.01,结果还是一样
没办法了,只有通过测试机(rails-1.8.6-p10+rails1.2.5+mongrel1.0.1)来测试,通过httperf高负载请求
几个访问量比较大的url, 发现mongrel1.0.1的内存并没有明显变化
实在找不到北,于是借助网上一片文章
http://scottstuff.net/blog/articles/2006/08/17/memory-leak-profiling-with-rails
这篇文章介绍了一段代码来检测内存泄漏,遗憾的是对于如何通过这段代码搞定他自己的问题
一笔带过
代码如下:

class MemoryProfiler
DEFAULTS
= {:delay => 10 ,:string_debug => false}

def self.start(opt = {})
opt
= DEFAULTS.dup.merge(opt)

Thread.newdo
prev
= Hash.new(0)
curr
= Hash.new(0)
curr_strings
= []
delta
= Hash.new(0)

file
= File.open( ' log/memory_profiler.log ' , ' w ' )

loopdo
begin
GC.start
curr.clear

curr_strings
= []ifopt[:string_debug]

ObjectSpace.each_objectdo
| o |
curr[o.
class ] += 1 # Marshal.dump(o).sizerescue1
ifopt[:string_debug]ando. class == String
curr_strings.pusho
end
end

ifopt[:string_debug]
File.open(
" log/memory_profiler_strings.log.#{Time.now.to_i} " , ' w ' )do | f |
curr_strings.sort.eachdo
| s |
f.putss
end
end
curr_strings.clear
end

delta.clear
(curr.keys
+ delta.keys).uniq.eachdo | k,v |
delta[k]
= curr[k] - prev[k]
end

file.puts
" Top20 "
delta.sort_by{
| k,v |- v.abs}[0.. 19 ].sort_by{ | k,v |- v}.eachdo | k,v |
file.printf
" %+5d:%s(%d) " ,v,k.name,curr[k]unlessv == 0
end
file.flush

delta.clear
prev.clear
prev.updatecurr
GC.start
rescueException
=> err
STDERR.puts
" **memory_profilererror:#{err} "
end
sleepopt[:delay]
end
end
end
end

源文档 < http://scottstuff.net/blog/articles/2006/08/17/memory-leak-profiling-with-rails>
为了能 更清楚地知道原因,我把这段代码直接加到测试机的environment.rb中,并在后面在补上
MemoryProfiler.start
这并非良好的代码组织方式,但是在时间仓促的情况下确实达到了效果,我通过
在项目的根目录下执行tail -f log/memory_profiler.log
看到了结果内似如下:
Top 20
+
252 :String( 33975 )
+
53 :Array( 1751 )
+
23 :Hash( 376 )
+
8 :Time( 67 )
+
6 :MatchData( 10 )
+
5 :HashWithIndifferentAccess( 10 )
+
3 :StringIO( 9 )
+
2 :Bignum( 21 )
+
2 :CGI::Session( 4 )
+
2 :ActionController::CgiRequest( 4 )
+
2 :ActionController::Flash::FlashHash( 4 )
+
2 :ActionController::CgiResponse( 4 )
+
2 :Digest::MD5( 2 )
+
2 :Regexp( 1172 )
+
1 :Mongrel::HttpResponse( 3 )
Top
20
+
2 :Proc( 454 )
+
1 :IOError( 6 )
+
1 :Mysql::Error( 6 )
+
1 :Mysql::Net( 7 )
-
1 :Mongrel::HttpParams( 2 )
-
1 :Mongrel::HeaderOut( 2 )
-
1 :Mongrel::HttpRequest( 2 )
-
1 :ActionController::CookieJar( 2 )
-
1 :CGI::Cookie( 2 )
-
1 :Thread( 5 )
-
1 :Float( 61 )
-
1 :( 1 )
结果中的每一行 表示每个对象在内存中的个数(后面的数字)和增减变化(前面的数字),每10秒计算一次,排出内存中的数量前20
如果你发现某个对象在内存中的个数一直高居不下,那说确实有问题
注意:如果我使用lighttpd,那么上面的结果是不会显示,也就是说连日志文件都不会产生,不知咋回事
用在测试机上我没有发现什么异常
不得已用在正式机上,确实看到了变化,我们自定义个某几个对象的内存数一直在增长,显然没有被垃圾回收的迹象,于是开始根据这几个对象查代码,查来查去也没查出个所以然。
正式机不行,但测试机是可以的,难道是因为环境的原因,采用最后一招,将正式机的环境改的和测试机一样, 结果问题就好,经过两天的观察,系统很稳定, 是不是已不存在泄漏还不敢说,但至少没有明显的泄漏,这个问题再进一步观察。
但令我疑惑的是难道ruby-1.8.5-p12这个有问题?后来我把这个ruby-1.8.5-p12装到原来是正常的测试机也出现问题了。

你可能感兴趣的:(Rails,Ruby,lighttpd,MySQL,.net)