11

我最近推出了一个新的 Ruby on Rails 应用程序,它在开发模式下运行良好。启动后我一直在体验正在使用的内存不断增加:

来自 New Relic、Dyno 内存使用情况的屏幕转储

更新:当这个来自 New Relic 的屏幕转储被拍摄时。 我已经安排了每小时重新启动一次网络测功机(两个网络测功机中的一个)。 因此,它没有达到 500Mb 的崩溃级别,实际上它有点像锯齿状图案。 这个问题根本没有解决,只是一些症状。 如您所见,早上并不那么忙,但下午更忙。

更新:当这个屏幕转储(下一个)来自 New Relic 时。我已经安排了每小时重新启动一次网络测功机(两个网络测功机中的一个)。因此,它没有达到 500Mb 的崩溃级别,实际上它有点像锯齿状图案。这个问题根本没有解决,只是一些症状。如您所见,早上并不那么忙,但下午更忙。我在 11.30 上传了一个小细节,即使它出现在统计数据中,它也不会影响问题。

还可以注意到,即使图表显示 AVG 内存,MIN 内存仍在不断增加。即使图表似乎在图表中暂时下降,最小内存保持不变或增加。MIN 内存永远不会减少!

该应用程序将(无需重新启动测功机)增加内存,直到达到 Heroku 的最大级别,并且应用程序因执行过期类型的错误而崩溃。

我不是一个优秀的程序员,但我之前做过一些应用程序,没有遇到过这类问题。

已执行故障排除

A. 我认为问题出在 application_controller 中的 before_filter 中(应用程序控制器中的变量会导致 Rails 中的内存泄漏吗?)但这不是问题。

B. 我安装了 oink 但它没有给出任何结果(根本)。它会创建一个 oink.log,但在我运行“heroku run oink -m log/oink.log”时不会给出任何结果,无论阈值是多少。

C. 我试过 bleak_house 但它已被弃用并且无法安装

D. 我在谷歌上搜索并阅读了该主题的大多数文章,但我并不聪明。

E. 我很想测试 memprof 但我无法安装它(我有 Ruby 1.9x 并且不知道如何将它降级到 1.8x)

我的问题:

Q1。我真正想知道的是每个请求都在增加的变量的名称,或者至少哪个控制器使用的内存最多。

Q2。下面代码中的控制器会增加内存吗?

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 或者垃圾收集器会处理这个问题?

Q3。我要寻找的主要内容是什么?现在我根本无法缩小范围。我不知道要深入研究代码的哪一部分,也不知道要查找什么。

Q4。万一我真的解决不了问题。是否有任何在线咨询服务可以发送我的代码并让他们找到问题?

谢谢!

更新。收到评论后,它可能与会话有关。这是我猜可能不好的代码的一部分:

# 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 控制器。当通过我的礼物生成引擎生成了一些礼物时,我将输入保存在会话中(以防他们想在以后使用该信息)。我从不杀死或过期这些会话,以防万一这可能导致内存增加。

再次更新:我删除了这段代码,但内存仍然增加,所以我猜这部分不是它,但类似的代码可能会导致错误?

4

2 回答 2

5

这不太可能是我们的related_feed_categories 引起的。

您是否使用大量文件?

您将会话数据保留多长时间?看起来您有一个电子商务网站,您是否在会话中保存对象?

基本上,我认为是文件、会话或服务器崩溃时刷新的临时数据增加(memcache?)。

在半夜,我猜你的顾客少了。您可以在高峰时段发布相同的内存图表吗?

它可能与这个问题有关:内存在一个空的 Rails 应用程序中无限增长

更新 :

Rails 不会在客户端存储所有数据。我不记得默认存储,除非您选择 cookie::store,否则 rails 只会发送 session_id 之类的数据。

它们是关于会话的一些指南,ActiveRecord::SessionStore 似乎是性能目的的最佳选择。而且您不应该在会话中保留大型对象或机密数据。更多关于这里的会议:http: //guides.rubyonrails.org/security.html#what-are-sessions

在 2.9 部分,你有一个关于销毁会话的解释,在一段时间内未使用。

我建议您存储提供搜索结果的 url,而不是将对象存储在会话中。您甚至可以将其存储在数据库中,从而可以为您的客户节省少量研究,和/或默认加载最后使用的数据。

但是在这些阶段,我们仍然不能完全确定会议是罪魁祸首。为了确保这一点,您可以在测试服务器上尝试使用过期会话对您的应用程序进行压力测试。所以基本上,你创建了大量的会话,也许 20 分钟后 rails 不得不压制它们。如果您发现内存消耗有任何差异,它将缩小范围。

第一种情况:会话到期时内存显着下降,您知道这是与会话相关的。

第二种情况:内存以更快的速度增加,但在会话到期时不下降,您知道它与用户相关,但与会话无关。

第三种情况:没有任何变化(通常内存增加),所以你知道它不依赖于用户数量。但我不知道是什么原因造成的。

当我说压力测试时,我指的是大量会话,而不是真正的压力测试。您需要的会话数取决于您的平均用户数。如果您有 50 个用户,那么在您的应用程序崩溃之前,20 -30 个会话可能非常重要。因此,如果您手动拥有它们,请配置更高的过期时间限制。我们只是在寻找内存消耗的差异。

更新 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-反对拒绝服务/

简而言之,符号会一直保存在内存中,直到您重新启动 ruby​​。因此,如果使用随机名称创建符号,内存将会增长,直到您的应用程序崩溃。Strings 不会发生这种情况,它们是 GCed。

有点旧,但对 ruby​​ 1.9.x 有效试试这个:Symbol.all_symbols.size

更新 4:

因此,您的符号可能是内存泄漏。现在我们仍然需要找到它发生的位置。使用 Symbol.all_symbols。它为您提供列表。我想你可以将它存储在某个地方,并与新数组进行比较,以查看添加了什么。

它可能是 i18n,也可能是像 i18n 这样以隐式方式生成的其他东西。但无论如何,这可能会生成名称中带有随机数据的符号。然后这些符号就再也不会使用了。

于 2012-09-27T14:13:30.223 回答
1

假设category_from_feed返回一个字符串(或者可能是一个符号),增加 300MB 的幅度是不太可能的。您可以通过对此进行分析来粗略得出结论:

4_000_000.times {related_feed_categories << "Loooooooooooooong string" }

此代码段会将内存使用量提高约 110MB。

我会查看读取文件然后不关闭它的数据库连接或方法。我可以看到它与提要有关,这可能意味着您可能正在使用 XML。这也可以作为一个起点。


将其发布为答案,因为这在评论中看起来很糟糕:/

于 2012-09-27T13:44:32.180 回答