【问题标题】:Get current ruby process memory usage获取当前 ruby​​ 进程内存使用情况
【发布时间】:2011-11-05 11:02:57
【问题描述】:

我想格式化我的Logger 输出以包含当前内存使用情况,以用于长时间运行的进程。

Ruby 有没有为此内置的东西,有点像 PHP 的 memory_get_usage()?还是我必须执行一些 shell 命令才能从 ps 获取它?

【问题讨论】:

  • 或许看看这个问题:stackoverflow.com/questions/4132916/…
  • 我想我曾经听说过 Ruby 1.9.2 有一个内存分析器。
  • 请注意,使用依赖运行外部命令的解决方案将其添加到日志中可能不是一个好主意。在 `backticks` 中执行代码时,ruby 的工作方式是当前的 ruby​​ 进程将被分叉,直到执行完成。每次执行代码时,这会使程序的内存消耗加倍。您很可能会遇到内存不足错误。 OS-gem 也这样做。

标签: ruby memory process


【解决方案1】:

操作系统 gem 有一个 rss_bytes 方法。

require "os"
puts "#{OS.rss_bytes / 1_000_000} MB"

【讨论】:

【解决方案2】:

在这里以其他形式提到过,但我发现这是最简单的咒语,至少在 Mac OS 上是这样:

`ps -o rss #{Process.pid}`.lines.last.to_i

来自man ps

rss   the real memory (resident set) size of the process (in 1024 byte units).

【讨论】:

    【解决方案3】:

    时间已经过去了,现在有一个宝石:get_process_mem

    require 'get_process_mem'
    mem = GetProcessMem.new
    puts "Memory used : #{mem.mb.round(0)} MB"
    

    【讨论】:

    • 你能演示一下如何使用它吗?
    【解决方案4】:

    NewRelic gem 通过MemorySampler class 为许多操作系统和 ruby​​ 运行时提供简单的 RSS 使用实现。

    在您的Gemfile 中包含newrelic_rpm gem 并调用它:

    NewRelic::Agent::Samplers::MemorySampler.new.sampler.get_sample
    

    它返回当前进程作为 RSS 持有的内存兆字节数。

    实现更喜欢可用的进程内计数器 (jruby),在 Linux 上使用 /proc/#{$$}/status,在其他任何地方回退到 ps

    【讨论】:

    • 感觉这应该是正确的答案,因为它避免了使用反引号和产生新进程。如果您已经担心内存使用情况,那将是一条糟糕的道路
    • @us 除了它确实产生了一个新进程 - 即ps,并且以与接受的答案非常相似的方式,针对不同平台进行额外处理:)(请查看“MemorySampler类”链接上面)
    • 它会生成一个ps 进程作为非 Linux 操作系统的最终后备。在撰写本文时,我无法找到从正在运行的进程中获取此信息的任何其他方式。我认为这些天在别处描述的os gem 可能是更好的选择。
    • 我收回了这一点,实际上,os gem 使用相同的算法,最终在 Linux 上生成 psgithub.com/rdp/os/blob/a7256aa1eebdbab545212b7330131126f973aa14/…
    【解决方案5】:

    在 Ruby 上使用外部命令(如 ps)通过使用反引号将在运行命令期间分叉当前进程。这意味着,如果您的 Ruby 进程消耗 300mb,那么您将需要另外 300mb 才能运行这些`ps -o rss #{$$}`.strip.split.last.to_i 解决方案中的任何一个。

    在基于 linux 的系统上,您可以通过读取 /proc/PID/statm 来获取进程内存信息。第二个字段是以内核页数为单位的驻留集大小。将 RSS 页面转换为字节需要您计算内核页面大小(很可能是 4096)。

    这里是如何获取 rss(以千字节为单位)的示例代码,适用于 Linux。我不知道如何在 OSX 或其他系统上执行此操作。

    module MemInfo
      # This uses backticks to figure out the pagesize, but only once
      # when loading this module.
      # You might want to move this into some kind of initializer
      # that is loaded when your app starts and not when autoload
      # loads this module.
      KERNEL_PAGE_SIZE = `getconf PAGESIZE`.chomp.to_i rescue 4096 
      STATM_PATH       = "/proc/#{Process.pid}/statm"
      STATM_FOUND      = File.exist?(STATM_PATH)
    
      def self.rss
        STATM_FOUND ? (File.read(STATM_PATH).split(' ')[1].to_i * KERNEL_PAGE_SIZE) / 1024 : 0
      end
    end
    
    # >> MemInfo.rss
    # => 251944
    

    【讨论】:

    • 这适用于旧版本的 Ruby,但 Ruby 从 2.0 开始对写时复制 (COW) 友好。
    • 即使在旧版本的 Ruby 中,这个答案也是错误的。 fork()总是在写入时复制,并且在分叉之后,ruby 会立即调用exec() 的某种风格。所以这个过程还不够长,不足以让任何“不友好”的事情发生。
    【解决方案6】:

    你可以简单地使用这个 puts 语句

    puts 'RAM USAGE: ' + `pmap #{Process.pid} | tail -1`[10,40].strip
    

    【讨论】:

      【解决方案7】:

      一年前试图解决这个问题时,我做了很多在线研究和 API 挖掘,只能通过对 ps 的系统调用来解决。

      在 OS X 10.7.2 和 Red Hat 4.1.2-13(在 EC2 上):

      pid, size = `ps ax -o pid,rss | grep -E "^[[:space:]]*#{$$}"`.strip.split.map(&:to_i)
      

      这会获取进程的常驻内存大小(以千字节为单位)并将其放入大小变量中。

      稍加努力就可以清理干净,但大部分时间都花在调用 ps 并捕获其输出上,所以我认为不值得花时间。

      【讨论】:

      • 如果你只是 ps -o rss -p #{$$}.chomp.split("\n").last.to_i 可能会更容易
      • 如另一个答案中所述,如果您的 pid 为 1234 并且有另一个 pid 为 12345 的进程,这可能/会给您错误的结果。
      • 应该注意这个解决方案是平台相关的。
      • 看来size = `ps -o rss= -p #{$$}`.to_iputs "%.1fMB used" % [`ps -o rss= -p #{$$}`.to_f/1024] 更好更短地完成工作。它适用于 Mac 和 Ubuntu
      猜你喜欢
      • 1970-01-01
      • 2010-10-24
      • 2011-05-07
      • 2016-06-22
      • 2015-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-30
      相关资源
      最近更新 更多