小记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).size rescue 1
            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
" Top 20 "
          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_profiler error: #{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内存泄漏)