【问题标题】:Memory leak with large number of SQL Logging strings in memory内存中存在大量 SQL 日志记录字符串的内存泄漏
【发布时间】:2013-11-19 09:11:03
【问题描述】:

我的应用在 Puma (2.4) 集群模式下运行,有 4 个工作人员。 最初,它们总共使用不到 2GB 的 RAM,但会不断增长,最终在运行 20 小时后占用 7GB。

通过使用 ObjectSpace,我发现字符串对象的数量增加得非常快,每个 worker 中的对象从大约 300k 增加到 4-5 百万个。

然后我使用以下脚本将这些字符串按前 60 个字符分组并执行计数:

counts = Hash.new(0) 
ObjectSpace.each_object do |o| 
  next unless (o.class == String) 
  counts[o[0,60]] += 1 
end
counts = counts.to_a.sort_by(&:last);
puts counts[-10..-1]

事实证明,这些字符串中的大多数都是来自 Active Record 的 SQL 日志记录

ObjectSpace.count_objects
# result
{
     :TOTAL => 2439593,
      :FREE => 209200,
  :T_OBJECT => 65944,
   :T_CLASS => 11343,
  :T_MODULE => 2003,
   :T_FLOAT => 13,
  :T_STRING => 1821445,
  :T_REGEXP => 6570,
   :T_ARRAY => 157012,
    :T_HASH => 27477,
  :T_STRUCT => 1406,
  :T_BIGNUM => 1393,
    :T_FILE => 142,
    :T_DATA => 75081,
   :T_MATCH => 1334,
 :T_COMPLEX => 1,
:T_RATIONAL => 2809,
    :T_NODE => 51890,
  :T_ICLASS => 4530
}

# top 10 string
["PricingRule Exists: SELECT" , 74632]
[": SELECT COUNT(*) FROM `re" , 85454]
["CACHE: SELECT  `companies`" , 93045]
["PricingRule Load: SELECT  " , 114169]
["Page Load: SELECT  `pages`" , 140245]
[": SELECT COUNT(*) FROM `pa" , 182274]
["Customer Load: SELECT  `cu" , 191972]
["Company Load: SELECT  `com" , 253025]
["Page Load: SELECT `pages`." , 320267]
["DestinationCountry Load: S" , 413299]

我使用 Rails 4、Ruby 2、mysql2(v0.3.13) 并将日志级别设置为警告,但这些 SQL 字符串仍被存储并在内存中不断增加。

有人对这个问题有任何想法或经验吗?如果您能提供帮助,我将不胜感激。

谢谢!

【问题讨论】:

  • 几年前我在 EventMachine gem 上看到过类似的问题。你的 C 编程有多好?我们可能需要弄脏手。看看这个:blog.nelhage.com/2013/03/tracking-an-eventmachine-leak
  • 如果您按照那篇文章进行操作,您会意识到每个对象 1k 的 200 万个字符串对象只有 2G。你提到7G的内存使用量。要么你的字符串真的很长(在这种情况下你很幸运,因为你已经发现了问题)或者问题更深,你可能需要深入研究 C 代码。
  • @Chandranshu 感谢您的回复,每个工作人员有 200 万个字符串对象,有 4 个工作人员,它们最多可以占用 8GB,这似乎是泄漏的原因。
  • 哦,好的。然后你几乎把它钉牢了。您只需要查看哪些对象引用了这些字符串。由于所有者对象,字符串没有被垃圾收集。如果您尝试在臃肿的应用程序上执行此操作,将会很困难。只需尝试分析 10 分钟的 Objectspace。
  • 您可能已经知道这一点,但在开始分析“对象空间的 10 分钟”之前,请确保您手动运行一次垃圾收集器。

标签: mysql ruby-on-rails activerecord memory-leaks


【解决方案1】:

这些字符串可以来自 'sql.active_record' 事件,原因可能你订阅 'sql.active_record' 事件并将这些字符串保留在您的对象中,以便 GB 无法释放它们。

ActiveSupport::Notifications.subscribed(callback, "sql.active_record") do
end

使用后请务必退订。

【讨论】:

  • 哇,我没想到。我用它来分析我的一些 SQL,但从不认为这可能是我问题的根源。非常感谢你。
猜你喜欢
  • 2020-11-12
  • 2017-01-14
  • 1970-01-01
  • 1970-01-01
  • 2014-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-29
相关资源
最近更新 更多