首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >红宝石记忆泄漏(MRI)

红宝石记忆泄漏(MRI)
EN

Stack Overflow用户
提问于 2016-12-02 22:17:43
回答 1查看 528关注 0票数 11

我肯定遗漏了什么,但我用Ruby编写的每个应用程序似乎都漏了一些内存。我使用RubyMRI2.3,但在其他版本中我看到了相同的行为。

每当我编写一个在循环中执行某些任务的测试应用程序时,它都在缓慢地泄漏内存。

代码语言:javascript
复制
while true
   #do something
   sleep 0.1
end

例如,我可以写入数组,然后在循环中清除它,或者只发送http请求。

这里只是一个例子,但我有很多这样的例子:

代码语言:javascript
复制
require 'net/http'
require 'json'
require 'openssl'

class Tester

    def send_http some_json
        begin
            @uri = URI('SERVER_URL')
            @http = Net::HTTP.new(@uri.host, @uri.port)
            @http.use_ssl = true
            @http.keep_alive_timeout = 10
            @http.verify_mode = OpenSSL::SSL::VERIFY_NONE
            @http.read_timeout = 30
            @req = Net::HTTP::Post.new(@uri.path, 'Content-Type' => 'application/json')
            @req.body = some_json.to_json
            res = @http.request(@req)
        rescue Exception => e  
                puts e.message  
                puts e.backtrace.inspect  
        end
    end

    def run
        while true
            some_json = {"name": "My name"}
            send_http(some_json)
            sleep 0.1
        end
    end
end


Tester.new.run

我看到的泄漏很小,每小时可以是0.5毫巴。

我使用MemoryProfiler和GC::Profiler.enable运行了代码,这表明我没有泄漏。因此,必须有两种选择:

  1. C代码中存在内存泄漏。这可能是可能的,但我不使用任何外部宝石,所以我发现很难相信Ruby正在泄漏。
  2. 没有内存泄漏,这是某种Ruby内存管理机制。问题是,我能勇敢地看到记忆在增长。直到什么时候才会长出来?我需要等多少时间才能知道是泄漏还是现在?

同样的代码在JRuby中运行的很好,没有任何泄漏。

我很惊讶地读到一篇文章:

来自Joe的叠加重合流

Ruby的历史主要是作为文本处理的命令行工具,因此它重视快速启动和较小的内存占用。它不是为长时间运行的守护进程/服务器进程设计的。

如果写的是真的,而Ruby不把内存放回操作系统.我们总会有泄密的,对吧?

例如:

  1. Ruby要求从操作系统中获得内存。
  2. OS为Ruby提供内存。
  3. Ruby释放内存,但GC仍然没有运行。
  4. Ruby要求从操作系统中获得更多内存。
  5. OS为Ruby提供更多内存。
  6. Ruby运行GC,但为时已晚,因为Ruby已经问了两次。
  7. 等等等等。

我在这里错过了什么?

EN

回答 1

Stack Overflow用户

发布于 2020-12-21 17:07:00

查看GC压缩和(Un)冻结字符串文本

“相同”字符串不一定是相同的

在Ruby2.7.0之前,主线Ruby没有压缩垃圾收集。虽然我没有完全理解所有的内部结构,但要点是某些对象是不能收集垃圾的。由于您使用的是Ruby2.3,所以在处理内存分配问题时要记住这一点。其他非YARV可能会以不同的方式处理它们的内部部件,这就是为什么在使用替代引擎(如JRuby )时可能会看到变化的原因。

即使使用Ruby3.0.0-预览2,默认情况下,字符串文本不会被冻结。,所以当前的实现是每十分之一秒创建一个具有唯一对象ID的新字符串对象。请考虑以下几点:

代码语言:javascript
复制
3.times.map { 'foo'.__id__ }
#=> [240, 260, 280]

尽管字符串对象看起来是相同的,但是Ruby实际上是将每个对象作为内存中的唯一对象分配。因为循环迭代不是作用域门,所以那些字符串对象不能被YARV收集或压缩。

默认情况下启用冻结字符串文本

您也可能有其他问题,但您最大的问题似乎是将所有这些字符串文本无限期地保留在无止境的while-循环中。您可以通过使用冻结字符串文字来解决垃圾收集问题(这不是内存泄漏)。请考虑以下几点:

代码语言:javascript
复制
# run irb with universally-frozen string literals
RUBYOPT="--enable-frozen-string-literal" irb
代码语言:javascript
复制
3.times.map { 'foo'.__id__ }
#=> [240, 240, 240]

您也可以在代码中以其他方式解决这个问题,但是减少保留在作用域中的字符串文本的数量似乎是一个非常明智的起点。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40941701

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档