我最近推出了一个新的 Ruby on Rails 应用程序,它在开发模式下运行良好。启动后我一直在体验内存使用量不断增加:
更新:当这张来自 New Relic 的屏幕转储(下一个)被拍摄时。我已经安排了每小时重新启动一次网络测功机(两个网络测功机中的一个)。因此,它没有达到 500Mb 的崩溃级别,实际上它有点像锯齿状图案。这个问题根本没有解决,只是一些症状。如您所见,早上并不那么忙,但下午更忙。我在 11.30 上传了一个小细节,即使它出现在统计数据中,它也不会影响问题。
还可以注意到,即使图表显示 AVG 内存,MIN 内存仍在不断增加。即使图表似乎在图表中暂时下降,最小内存保持不变或增加。 MIN 内存永远不会减少!
应用程序将(无需重新启动测功机)增加内存,直到达到 Heroku 的最大级别,并且应用程序因执行过期类型的错误而崩溃。
我不是一个优秀的程序员,但我之前做过一些应用程序,没有遇到过这类问题。
已进行故障排除
A.我认为问题出在 application_controller ( Will variables in application controller cause a memory leak in Rails? ) 中的 before_filter 中,但这不是问题。
B.我安装了 oink 但它没有给出任何结果(根本)。它会创建一个 oink.log,但在我运行“heroku run oink -m log/oink.log”时不会给出任何结果,无论阈值是多少。
C.我尝试了 bleak_house,但它已被弃用,无法安装
D.我已经在 Google 上搜索并阅读了该主题中的大多数文章,但我并不聪明。
E.我很想测试 memprof 但我无法安装它(我有 Ruby 1.9x 并且真的不知道如何将它降级到 1.8x)
我的问题:
第一季度。我真正想知道的是每个请求都在增加的变量的名称,或者至少是哪个 Controller 使用的内存最多。
第二季度。下面代码中的 Controller 会增加内存吗?
related_feed_categories = []
@gift.tags.each do |tag|
tag.category_connections.each do |cc|
related_feed_categories << cc.category_from_feed
end
end
(抱歉,出于某种原因,SO 不会重新格式化代码以使其易于阅读)。
之后我是否需要用“related_feed_categories = nil”来“杀死”related_feed_categories,还是垃圾收集器会处理这个问题?
第三季度。我要寻找的主要内容是什么?现在我根本无法缩小范围。我不知道要深入查看代码的哪一部分,也不知道要查找什么。
第四季度。万一我真的解决不了问题。是否有任何在线咨询服务可以发送我的代码并让他们找到问题?
谢谢!
更新。收到评论后,它可能与 session 有关。这是我猜可能不好的部分代码:
# Create sessions for last generation
friend_data_arr = [@generator.age, @generator.price_low, @generator.price_high]
friend_positive_tags_arr = []
friend_negative_tags_arr = []
friend_positive_tags_arr << @positive_tags
friend_negative_tags_arr << @negative_tags
session["last_generator"] = [friend_data_arr, friend_positive_tags_arr, friend_negative_tags_arr]
# Clean variables
friend_data_arr = nil
friend_positive_tags_arr = nil
friend_negative_tags_arr = nil
它在 generator#show Controller 中使用。当通过我的礼物生成引擎生成了一些礼物时,我将输入保存在 session 中(以防他们想在以后使用该信息)。我从不终止或终止这些 session ,以防这可能导致内存增加。
再次更新:我删除了这段代码,但内存仍然增加,所以我猜这部分不是它但类似的代码可能会导致错误?
最佳答案
这不太可能是我们的related_feed_categories 引起的。
您是否使用了很多文件?
您将 session 数据保留多长时间?看起来您有一个电子商务网站,您是否在 session 中保存对象?
基本上,我认为是文件,或 session ,或服务器崩溃时刷新的临时数据增加(memcache?)。
在半夜,我猜你的顾客少了。你能在高峰时段发布相同的内存图表吗?
可能与这个问题有关:Memory grows indefinitely in an empty Rails app
更新:
Rails 不会在客户端存储所有数据。我不记得默认存储,除非您选择 cookie::store,否则 rails 只会发送 session_id 之类的数据。
它们是关于 session 的一些指南,ActiveRecord::SessionStore 似乎是性能目的的最佳选择。而且您不应该在 session 中保留大型对象或 secret 数据。更多关于 session 的信息:http://guides.rubyonrails.org/security.html#what-are-sessions
在 2.9 部分,你有一个关于销毁 session 的解释,在一段时间内未使用。
我建议您存储提供搜索结果的 url,而不是将对象存储在 session 中。您甚至可以将其存储在数据库中,从而可以为您的客户节省少量研究,和/或默认加载上次使用的数据。
但在这个阶段,我们仍然不能完全确定 session 是罪魁祸首。为了确保这一点,您可以在测试服务器上尝试使用过期 session 对您的应用程序进行压力测试。所以基本上,你创建了大量的 session ,也许 20 分钟后 rails 不得不压制它们。如果您发现内存消耗有任何差异,它会缩小范围。
第一种情况: session 到期时内存显着下降,您知道这是与 session 相关的。
第二种情况:内存以更快的速度增加,但在 session 到期时不下降,你知道它与用户相关,但与 session 无关。
第三种情况:没有任何变化(通常内存增加),所以你知道它不依赖于用户数量。但我不知道是什么原因造成的。
当我说压力测试时,我指的是大量 session ,而不是真正的压力测试。您需要的 session 数取决于您的平均用户数。如果您有 50 个用户,那么在您的应用程序崩溃之前,20 -30 个 session 可能非常重要。因此,如果您手动拥有它们,请配置更高的过期时间限制。我们只是在寻找内存消耗的差异。
更新 2:
所以这很可能是内存泄漏。所以使用对象空间,它有一个 count_objects 方法,它将显示当前使用的所有对象。它应该缩小范围。当内存已经增加很多时使用它。
否则,你有 bleak_house,一个能够发现内存泄漏的 gem,仍然 ruby 用于内存泄漏的工具不如 java 有效,但值得一试。
Github:https://github.com/evan/bleak_house
更新 3:
这可能是一种解释,这并不是真正的内存泄漏,但它会增加内存: http://www.tricksonrails.com/2010/06/avoid-memory-leaks-in-ruby-rails-code-and-protect-against-denial-of-service/
简而言之,符号会一直保存在内存中,直到您重新启动 ruby。因此,如果使用随机名称创建符号,内存将会增长,直到您的应用程序崩溃。字符串不会发生这种情况,它们是 GCed。
有点旧,但适用于 ruby 1.9.x 试试这个:Symbol.all_symbols.size
更新 4:
所以,您的符号可能是内存泄漏。现在我们仍然需要找到它发生的地方。使用 Symbol.all_symbols。它为您提供列表。我想你可以将它存储在某个地方,并与新数组进行比较,以查看添加了什么。
它可能是 i18n,也可能是像 i18n 这样以隐式方式生成的其他东西。但无论如何,这可能会生成名称中带有随机数据的符号。然后这些符号就再也不用了。
关于ruby-on-rails - Rails 应用程序中的内存不断增加,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12578344/