现在的位置: 首页 > 综合 > 正文

小记rails内存泄漏

2013年01月03日 ⁄ 综合 ⁄ 共 3118字 ⁄ 字号 评论关闭
 

刚刚上了一个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的内存并没有明显变化
 
实在找不到北,于是借助网上一片文章
这篇文章介绍了一段代码来检测内存泄漏,遗憾的是对于如何通过这段代码搞定他自己的问题
一笔带过
 
代码如下:

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

 
 
 
为了能 更清楚地知道原因,我把这段代码直接加到测试机的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装到原来是正常的测试机也出现问题了。

 

抱歉!评论已关闭.