如何在Ruby代码中追踪内存泄漏?

 邹昕明 发布于 2023-02-06 11:17

在查找内存泄漏时,我没有发现ruby-prof非常有用,因为你需要一个修补的Ruby解释器.在Ruby 2.1中,跟踪对象分配变得更加容易.也许这是自己探索这个的最佳选择.

我推荐博客文章Ruby 2.1:objspace.so由tmml谁是Ruby核心开发人员之一.基本上,您可以在调试应用程序时获取大量信息:

ObjectSpace.each_object{ |o| ... }
ObjectSpace.count_objects #=> {:TOTAL=>55298, :FREE=>10289, :T_OBJECT=>3371, ...}

require 'objspace'
ObjectSpace.memsize_of(o) #=> 0 /* additional bytes allocated by object */
ObjectSpace.count_tdata_objects #=> {Encoding=>100, Time=>87, RubyVM::Env=>17, ...}
ObjectSpace.count_nodes #=> {:NODE_SCOPE=>2, :NODE_BLOCK=>688, :NODE_IF=>9, ...}
ObjectSpace.reachable_objects_from(o) #=> [referenced, objects, ...]
ObjectSpace.reachable_objects_from_root #=> {"symbols"=>..., "global_tbl"=>...} /* in 2.1 */

使用Ruby 2.1,您甚至可以开始跟踪新对象的分配并收集有关每个新对象的元数据:

require 'objspace'
ObjectSpace.trace_object_allocations_start

class MyApp
  def perform
    "foobar"
  end
end

o = MyApp.new.perform
ObjectSpace.allocation_sourcefile(o) #=> "example.rb"
ObjectSpace.allocation_sourceline(o) #=> 6
ObjectSpace.allocation_generation(o) #=> 1
ObjectSpace.allocation_class_path(o) #=> "MyApp"
ObjectSpace.allocation_method_id(o)  #=> :perform

使用pry和pry-debugger并开始探索您认为可能会增长的内存堆,分别尝试代码中的不同段.在Ruby 2.1之前,我总是依赖ObjectSpace.count_objects并计算结果的差异,以查看一个对象类型是否特别增长.

当生成的对象数量在迭代期间重新测试回到更小的量而不是继续增长时,垃圾收集正常工作.无论如何,垃圾收集器应该一直运行,您可以通过查看垃圾收集器统计信息来安抚自己.

根据我的经验,这是String或Symbol(T_STRING).ruby 2.2.0之前的符号没有被垃圾收集,因此请确保您的CSV或其中的部分内容未在途中转换为符号.

如果您感觉不舒服,请尝试使用JRuby在JVM上运行代码.至少使用像VisualVM这样的工具可以更好地支持内存分析.

1 个回答
  • 在查找内存泄漏时,我没有发现ruby-prof非常有用,因为你需要一个修补的Ruby解释器.在Ruby 2.1中,跟踪对象分配变得更加容易.也许这是自己探索这个的最佳选择.

    我推荐博客文章Ruby 2.1:objspace.so由tmml谁是Ruby核心开发人员之一.基本上,您可以在调试应用程序时获取大量信息:

    ObjectSpace.each_object{ |o| ... }
    ObjectSpace.count_objects #=> {:TOTAL=>55298, :FREE=>10289, :T_OBJECT=>3371, ...}
    
    require 'objspace'
    ObjectSpace.memsize_of(o) #=> 0 /* additional bytes allocated by object */
    ObjectSpace.count_tdata_objects #=> {Encoding=>100, Time=>87, RubyVM::Env=>17, ...}
    ObjectSpace.count_nodes #=> {:NODE_SCOPE=>2, :NODE_BLOCK=>688, :NODE_IF=>9, ...}
    ObjectSpace.reachable_objects_from(o) #=> [referenced, objects, ...]
    ObjectSpace.reachable_objects_from_root #=> {"symbols"=>..., "global_tbl"=>...} /* in 2.1 */
    

    使用Ruby 2.1,您甚至可以开始跟踪新对象的分配并收集有关每个新对象的元数据:

    require 'objspace'
    ObjectSpace.trace_object_allocations_start
    
    class MyApp
      def perform
        "foobar"
      end
    end
    
    o = MyApp.new.perform
    ObjectSpace.allocation_sourcefile(o) #=> "example.rb"
    ObjectSpace.allocation_sourceline(o) #=> 6
    ObjectSpace.allocation_generation(o) #=> 1
    ObjectSpace.allocation_class_path(o) #=> "MyApp"
    ObjectSpace.allocation_method_id(o)  #=> :perform
    

    使用pry和pry-debugger并开始探索您认为可能会增长的内存堆,分别尝试代码中的不同段.在Ruby 2.1之前,我总是依赖ObjectSpace.count_objects并计算结果的差异,以查看一个对象类型是否特别增长.

    当生成的对象数量在迭代期间重新测试回到更小的量而不是继续增长时,垃圾收集正常工作.无论如何,垃圾收集器应该一直运行,您可以通过查看垃圾收集器统计信息来安抚自己.

    根据我的经验,这是String或Symbol(T_STRING).ruby 2.2.0之前的符号没有被垃圾收集,因此请确保您的CSV或其中的部分内容未在途中转换为符号.

    如果您感觉不舒服,请尝试使用JRuby在JVM上运行代码.至少使用像VisualVM这样的工具可以更好地支持内存分析.

    2023-02-06 11:18 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有