Ruby Memory Leak (MRI)

I need to skip something, but every application that I write in Ruby seems to leak into some kind of memory. I use Ruby MRI 2.3, but I see the same behavior with other versions.

Whenever I write a test application that does something inside a loop, it slowly flows in memory.

while true #do something sleep 0.1 end 

For example, I can write to an array and then clear it in a loop or just send an HTTP request.

Here is just one example, but I have many examples:

 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 

The leak that I see is very small, it can be 0.5 mb every hour.

I ran the code with MemoryProfiler and with GC :: Profiler.enable, and this shows that I have no leaks. Thus, it should be two options:

  • C code has a memory leak. It may be possible, but I do not use any external stones, so I find it hard to believe that Ruby is leaking.

  • There is no memory leak, and it is a kind of Ruby memory management mechanism. The fact is that I can defiantly see the growth of memory. Until it grows up? How much do I need to find out if there is a leak or now?

The same code works fine with JRuby without any leaks.

I was amazed to read the message:

overlapping stack from Joe Edgar:

The history of Rubys is basically a command line tool for word processing, and so it appreciates fast startup and a small amount of memory. It was not designed for long daemon / server processes

If what is written is true, and Ruby does not free memory back to the OS, then ... We will always have a leak, right?

For instance:

  • Ruby is requesting memory from the OS.
  • The OS provides memory for Ruby.
  • Ruby frees memory, but GC still did not start.
  • Ruby is requesting more memory from the OS.
  • The OS provides more memory for Ruby.
  • Ruby launches GC, but it's too late, as Ruby repeated it twice.
  • And so on and on.

What am I missing here?

+6
source share

Source: https://habr.com/ru/post/1012847/


All Articles