gpt4 book ai didi

Ruby 内存泄漏 (MRI)

转载 作者:行者123 更新时间:2023-12-03 15:15:08 30 4
gpt4 key购买 nike

我一定遗漏了一些东西,但我用 Ruby 编写的每个应用程序似乎都在泄漏一些内存。我使用 Ruby MRI 2.3,但我看到其他版本的行为相同。

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

while true
#do something
sleep 0.1
end

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

这里只是一个例子,但我有很多这样的例子:
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 mb。

我用 MemoryProfiler 和 GC::Profiler.enable 运行了代码,它表明我没有泄漏。所以它必须是2个选项:
  • C 代码中存在内存泄漏。这可能是可能的,但我不使用任何外部 gem,所以我很难相信 Ruby 正在泄漏。
  • 没有内存泄漏,这是某种 Ruby 内存管理机制。问题是我可以目瞪口呆地看到内存在增长。到什么时候才能长大?我需要等待多久才能知道是泄漏还是现在?

  • 相同的代码在 JRuby 上运行得非常好,没有任何泄漏。

    看了一篇文章,我很惊讶:

    stack overlflow
    来自乔埃德加:

    Ruby’s history is mostly as a command line tool for text processing and therefore it values quick startup and a small memory footprint. It was not designed for long-running daemon/server processes



    如果那里写的是真的,而 Ruby 没有将内存释放回操作系统,那么......我们总会有泄漏,对吧?

    例如:
  • Ruby 向操作系统请求内存。
  • 操作系统为 Ruby 提供内存。
  • Ruby 释放了内存,但 GC 仍然没有运行。
  • Ruby 要求操作系统提供更多内存。
  • 操作系统为 Ruby 提供更多内存。
  • Ruby 运行 GC 但为时已晚,因为 Ruby 已经问过两次了。
  • 等等等等。

  • 我在这里缺少什么?

    最佳答案

    查看 GC 压缩和 (Un)frozen String Literals
    “相同”字符串不一定相同
    在 Ruby 2.7.0 之前,主线 Ruby 没有压缩垃圾收集。虽然我不完全了解所有内部结构,但要点是某些对象 couldn't be garbage collected .由于您使用的是 Ruby 2.3,因此在处理内存分配问题时需要牢记这一点。其他非 YARV 虚拟机可能会以不同方式处理其内部结构,这就是为什么在使用替代引擎(如 JRuby)时您可能会看到变化的原因。
    即使使用 Ruby 3.0.0-preview2,String literals aren't frozen by default ,因此您当前的实现是每十分之一秒创建一个具有唯一对象 ID 的新 String 对象。考虑以下:

    3.times.map { 'foo'.__id__ }
    #=> [240, 260, 280]
    尽管 String 对象看起来相同,但实际上 Ruby 将每个对象分配为内存中的唯一对象。因为循环迭代不是作用域门,所以 YARV 无法收集或压缩这些 String 对象。
    默认情况下启用卡住字符串文字
    您可能还有其他问题,但您最大的问题似乎很可能是将所有这些 String 文字无限期地保留在无限的 while 循环中。您可以使用 frozen String literals 解决垃圾收集问题(这不是内存泄漏)。反而。考虑以下:
    # run irb with universally-frozen string literals
    RUBYOPT="--enable-frozen-string-literal" irb
    3.times.map { 'foo'.__id__ }
    #=> [240, 240, 240]
    您也可以通过其他方式在代码中解决此问题,但减少保留在范围内的字符串文字的数量似乎是一个非常明智的起点。

    关于Ruby 内存泄漏 (MRI),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40941701/

    30 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com