13

我有一个带有捆绑程序的 Rails 2.3.10 应用程序。启动时内存占用非常大(开发模式下为 300MB)。

我想看看每个 gem 在启动时占用多少内存。

4

3 回答 3

19

我们遇到了一个问题,即没有流量或请求的基本 Rails 应用程序在启动时的占用空间约为 140MB。

我们使用以下方法来跟踪我们应用程序的 Gemfile 中指定的每个 gem 的内存需求,而无需尝试修补 bundler。

  1. 使用rails new myappname生成一个新的空 Rails 应用程序
  2. 将 Gemfile 从主项目复制到这个新的 rails 项目
  3. 运行bundle install,然后rails server确保可以启动 rails 服务器并加载所需的任何基本配置
  4. 打开 Gemfile,除了 rails gem 的规范外,require: false在每一行的末尾追加。确保使用一个名称指定但需要使用 :require => 'othergemname' 的任何其他 gem 使用较旧的 ruby​​ 哈希表示法,以便下面的模式匹配将捕获它。
  5. 再次运行bundle install以重新生成 Gemfile.lock
  6. 创建以下脚本,该脚本将手动使用 Gemfile 中指定的每个 gem,并记录 rails 进程之前和之后消耗的系统内存。

    # require_and_profile.rb
    def require_and_profile(gemname = nil)
      unless gemname
        puts "%-20s: %10s | %10s" % ['gem','increment','total']
        return
      end
      # This is how to get memory of calling process in OS X, check host OS for variants
      memory_usage = `ps -o rss= -p #{Process.pid}`.to_i / 1024.0
      require gemname
      puts "%-20s: %10.2f | %10.2f" % [ gemname, (`ps -o rss= -p #{Process.pid}`.to_i / 1024.0 - memory_usage), (`ps -o rss= -p #{Process.pid}`.to_i / 1024.0)]
    end
    
    pattern = /^[^#]*gem[ ]*['"]([^,'"]*)['"][ ,~>0-9\.'"]*(:require[ => ]*['"]([^'"]*)['"][, ])?/
    
    require_and_profile
    File.open('Gemfile').each do |line|
      if line.match(pattern)
      if line.match(pattern)[3]
        require_and_profile line.match(pattern)[3]
      else
          require_and_profile line.match(pattern)[1]
        end
      end
    end
    
  7. rails c

  8. load 'require_and_profile.rb'
  9. 输出显示每个 gem 增加了多少(以 MB 为单位)到基础应用程序占用空间(增量)以及包含 gem 后的总占用空间(总计)。

例如,这有助于我们确定,当我们只在 :asset 组中需要它时,我们一直在启动时需要资产同步。我们确实发现,在不同的启动过程中,每个 gem 的内存占用并不完全相同,但运行几次确实会向您显示哪些是需要内存的 gem 的模式。

于 2013-09-11T02:45:01.783 回答
14

现在使用 derailed gem 有一种更简单的方法:

添加到您的gemfile:

gem 'derailed', group: :development

然后在您的应用程序根目录的命令行上:

bundle exec derailed bundle:mem

这将打印出每个 gem 包含多少内存。

于 2016-04-26T21:33:26.717 回答
0

我会这样做:

  • 在捆绑器中找到需要所有宝石的地方。
  • 在需要每个 gem 之后,获取当前对象计数 ( c = 0; ObjectSpace.each_object { c += 1 })

通过这种方式,您将看到哪个 gem 导致实例化的对象最多,因此间接导致最多的内存使用。

不过有两个警告:

  • 内存使用量与对象的数量并没有真正的线性关系,但是您应该对哪些 gem 是最严重的违规者有一个足够好的估计
  • 正如已经指出的那样:gem 在需要时可能不会加载所有代码,因此当加载更多代码时,gem 可能会导致更多的内存使用......
于 2012-10-25T10:47:34.447 回答