You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何排查Rails中大量内存未被垃圾回收的问题?

Rails 6.1.7/Ruby 3.1.2 内存泄漏排查方案

问题背景

我们维护基于Ruby 3.1.2/Rails 6.1.7、Postgres的应用,此前因内部工具执行无分页ActiveRecord查询,导致部分实例内存飙升数十MB且数天无法释放。添加分页后大幅增长问题解决,但小负载场景下仍存在内存渐进式增长,需区分是内存碎片还是真正的内存泄漏,同时希望能查看运行中实例的内存对象图。

查看运行中实例内存对象图的方法

1. ObjectSpace + ruby-debug 实时分析

  • 在Rails控制台(生产环境操作需谨慎,避免长时间占用资源)中,用ObjectSpace遍历内存对象:
    • 统计特定类实例数量:ObjectSpace.each_object(ActiveRecord::Base).count
    • 查看对象引用链:对可疑对象执行debug(obj)(需安装ruby-debug),分析其引用关系,判断是否存在意外的持久化引用。
  • 注意:ObjectSpace会带来性能开销,使用后立即退出控制台。

2. derailed_benchmarks 深度内存分析

  • 安装derailed_benchmarks(建议仅在development组添加),针对Rails应用提供内存泄漏检测:
    • 查看Gem内存占用:bundle exec derailed bundle:mem
    • 模拟请求跟踪内存变化:bundle exec derailed perf:mem,对比多次请求后的对象留存情况,生成详细的对象分配报告。

3. heap_dump 生成内存快照

  • 安装heap_dump gem,在应用中触发快照生成:
    • 通过控制器动作或rake任务添加触发逻辑:HeapDump.dump('/tmp/heap_snapshot.json')
    • 对比不同时间点的快照,找出持续增长的对象集合,定位内存泄漏点。
  • 生产环境建议将快照输出到临时目录,避免占用过多磁盘空间。

区分内存碎片与内存泄漏的方法

  • 手动触发GC验证:在控制台执行GC.start; GC.start(连续两次确保完全回收),用get_process_mem查看内存:GetProcessMem.new.mb。若内存仍远高于基线,说明存在未回收对象;若回落但未到初始值,大概率是内存碎片。
  • 对比Web请求与控制台的内存行为:控制台执行查询后关闭即释放内存,但Web请求后不释放的话,可在请求末尾添加GC.start,观察内存变化:
    • 若内存回落,说明是GC时机问题;若不回落,说明对象被全局变量、单例对象或后台线程持有引用。
  • 检查后台线程与全局缓存:Rails 6.x默认memory_store为进程独立缓存,检查Rails.cache.stats查看缓存键数量,确认是否有未清理的大缓存项;同时排查后台线程是否持有请求对象的引用。

ActiveRecord相关排查点

  • 检查数据库连接状态:执行ActiveRecord::Base.connection_pool.stat,若存在未释放的连接,可能关联着结果集对象导致内存无法回收。
  • 排查关联预加载的隐藏引用:即使主结果集被销毁,预加载的关联对象若被全局观察者、回调等持久化引用,也会导致内存泄漏。可通过ObjectSpace.each_object(YourModel).select { |obj| obj.association(:related_model).loaded? }查看未回收的关联对象。

内容的提问来源于stack exchange,提问作者JakeRobb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 19:30:57