我肯定遗漏了什么,但我用Ruby编写的每个应用程序似乎都漏了一些内存。我使用RubyMRI2.3,但在其他版本中我看到了相同的行为。
每当我编写一个在循环中执行某些任务的测试应用程序时,它都在缓慢地泄漏内存。
while true
#do something
sleep 0.1
end例如,我可以写入数组,然后在循环中清除它,或者只发送http请求。
这里只是一个例子,但我有很多这样的例子:
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运行了代码,这表明我没有泄漏。因此,必须有两种选择:
同样的代码在JRuby中运行的很好,没有任何泄漏。
我很惊讶地读到一篇文章:
来自Joe的叠加重合流:
Ruby的历史主要是作为文本处理的命令行工具,因此它重视快速启动和较小的内存占用。它不是为长时间运行的守护进程/服务器进程设计的。
如果写的是真的,而Ruby不把内存放回操作系统.我们总会有泄密的,对吧?
例如:
我在这里错过了什么?
发布于 2020-12-21 17:07:00
查看GC压缩和(Un)冻结字符串文本
“相同”字符串不一定是相同的
在Ruby2.7.0之前,主线Ruby没有压缩垃圾收集。虽然我没有完全理解所有的内部结构,但要点是某些对象是不能收集垃圾的。由于您使用的是Ruby2.3,所以在处理内存分配问题时要记住这一点。其他非YARV可能会以不同的方式处理它们的内部部件,这就是为什么在使用替代引擎(如JRuby )时可能会看到变化的原因。
即使使用Ruby3.0.0-预览2,默认情况下,字符串文本不会被冻结。,所以当前的实现是每十分之一秒创建一个具有唯一对象ID的新字符串对象。请考虑以下几点:
3.times.map { 'foo'.__id__ }
#=> [240, 260, 280]尽管字符串对象看起来是相同的,但是Ruby实际上是将每个对象作为内存中的唯一对象分配。因为循环迭代不是作用域门,所以那些字符串对象不能被YARV收集或压缩。
默认情况下启用冻结字符串文本
您也可能有其他问题,但您最大的问题似乎是将所有这些字符串文本无限期地保留在无止境的while-循环中。您可以通过使用冻结字符串文字来解决垃圾收集问题(这不是内存泄漏)。请考虑以下几点:
# run irb with universally-frozen string literals
RUBYOPT="--enable-frozen-string-literal" irb3.times.map { 'foo'.__id__ }
#=> [240, 240, 240]您也可以在代码中以其他方式解决这个问题,但是减少保留在作用域中的字符串文本的数量似乎是一个非常明智的起点。
https://stackoverflow.com/questions/40941701
复制相似问题