Is it good practice to run Manual GC in ruby
Asked Answered
D

3

5

I read quite a lot on Google that ruby does not release back memory to the OS and I understand the as well because allocating memory from OS is a costly fair.

Which has led me to ask this

If a developer want the Ruby to release the memory back to OS from ruby how do they do it.

- I guess the answer is manually triggering a GC in Ruby.

But is it advisable to do (run manual GC) on a production application.

I'm thinking of creating a separate thread(or Actor) in Celluloid to start a GC at every 2 hours time.

Can anyone suggest. Is the above solution advisable for production.

Note: I think I also know GC.start (means stop the whole world in Ruby)

Note: Ruby Version 2.2.2 MRI Centos 4G RAM with 4 core.

And here is the reason for the question http://pastebin.com/rYdYwxLJ

Dictate answered 29/7, 2016 at 11:48 Comment(0)
W
8

I read quite a lot on Google that ruby does not release back memory to the OS and I understand the as well because allocating memory from OS is a costly fair.

That's simply not true. The Ruby Language doesn't say anything at all about releasing memory back to the OS. In fact, the Ruby Language doesn't say anything about memory, period.

There are a lot of different implementations of Ruby with a lot of different memory allocators and a lot of different garbage collectors. Some release memory back to the OS, some don't, some run on top of a managed runtime and don't even manage memory at all.

For example, JRuby running on J9 will release memory back to the OS. JRuby running on HotSpot with the G1 GC, ParallelScavenge GC, or ParallelOld GC will release memory back to the OS.

If a developer want the Ruby to release the memory back to OS from ruby how do they do it.

You don't. Either the implementation releases memory back to the OS, in which case you don't need to do anything, or it doesn't release memory back to the OS, in which you cannot do anything.

- I guess the answer is manually triggering a GC in Ruby.

If the implementation doesn't release memory back to the OS, then it doesn't release memory back to the OS. Period.

If the implementation does release memory back to the OS, then it will do that whether you manually trigger a GC or not.

By the way: you cannot manually trigger a GC in Ruby. You can suggest a GC (using GC::start), but not trigger it.

But is it advisable to do (run manual GC) on a production application.

Pretty much never. The GC knows better than you do whether it makes sense to run now or at a later time.

Note: I think I also know GC.start (means stop the whole world in Ruby)

No, GC::start simply suggests to do a GC. It does not force a GC. Also, GC does not mean stop-the-world. E.g. when running JRuby on the J9 JVM with the Metronome GC or running JRuby on the Azul Zing JVM with the Pauseless GC will never stop-the-world.

Note: Ruby Version 2.2.2

That's not the interesting bit. The interesting question is which implementation you are using, which garbage collector, and which OS. (And of course the versions and configuration settings for all of those.)

Wily answered 29/7, 2016 at 12:35 Comment(3)
Mittag Thanks for the answer the OS is unix based Centos to be precise. and the Ruby is the MRI Ruby. I will edit that in Question.Dictate
W Mittang and here is the Reason why I want the GC.start pastebin.com/rYdYwxLJ. Any I understand the consequence now.Dictate
In your pastebin example, the variable is still in scope. If you compartmentalize the top half of script in a method, it allows the possible GC as the variable falls out of scope (whether or not you've assigned nil to it). See: #14107898Closestool
W
4

You likely misunderstood what you have read via Google links. The memory, that Ruby (here and after I mean MRI as default Ruby implementation) does not release back to OS (so-called Ruby Heaps,) is not released to OS. Period.

You have no ability to force Ruby to release Ruby Heaps back to OS (besides cold restart of the whole application.)

What might be released back to OS, is released by Ruby internally and it is a bad practice by all means to call GC manually, in 99% of cases that will slow down the application, in the rest 1% this will have no effect at all.

Weichsel answered 29/7, 2016 at 11:58 Comment(2)
Disabling GC can sometimes improve speed, in very specific circumstances (e.g. you are generating millions of objects, with only a small overhead of temporary objects to care about during generation process).Mattiematting
@NeilSlater Yes, disabling GC might improve a speed in some cases, but I was preventing from manually running GC. And, in any case, such an action should not be done after a quick answer on SO :)Weichsel
A
0

The GC defaults are sufficient for typical use cases, however I can imagine the use case where long-running process allocates some memory, but then doesn't trigger GC conditions for some time which results in some memory being held. In that case it makes sense to me to call GC.start on production.

To answer the more general question of "Is it good practice to run Manual GC in ruby", I would say that it sometimes is. My use case: I had to invoke GC.start manually on production applications in some cases where external C-libraries were involved (I'm using MRI). As I understand it, they allocate memory which is not monitored by Ruby and therefore doesn't trigger GC.

Example of GC.start use case, using gdk_pixbuf2 gem and a high resolution image:

[1] pry(main)> 10.times do
[1] pry(main)*   GdkPixbuf::Pixbuf.new(file: 'tmp/high-res-small-size-16000x11000px.jpg')
[1] pry(main)*   puts "#{`ps -p #{Process.pid} -o 'rss='`.to_i / 1000}MB"
[1] pry(main)* end
897MB
1413MB
1929MB
2444MB
2960MB
3476MB
3991MB
4507MB
Killed
[1] pry(main)> 10.times do
[1] pry(main)*   GdkPixbuf::Pixbuf.new(file: 'tmp/high-res-small-size-16000x11000px.jpg')
[1] pry(main)*   GC.start
[1] pry(main)*   puts "#{`ps -p #{Process.pid} -o 'rss='`.to_i / 1000}MB"
[1] pry(main)* end

897MB
897MB
897MB
897MB
897MB
897MB
897MB
897MB
897MB
897MB
Aulea answered 29/8 at 14:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.