Reputation: 5962
I puzzled by some behaviour of ruby and how it manages memory.
I understand the Ruby GC (major or minor) behaviour i.e if the any objects count goes above there threshold value or limit (i.e heap_available_slots,old_objects_limit, remembered_shady_object_limit, malloc_limit). Ruby run/trigger a GC(major or minor).
And after GC if it can't find the enough memory Ruby allocate (basically malloc I assuming) more memory for the running program.
Also, It's a known fact that by does release back memory to the OS immediately.
Now ..
What I fail to understand how come Ruby releases memory (back to the OS) without triggering any GC.
Example
require 'rbtrace'
index = 1
array = []
while(index < 20000000) do
array << index
index += 1
end
sleep 10
print "-"
array=nil
sleep
Here is my example. If run the above code on ruby 2.2.2p95.
htop
display the RSS count of the process (test.rb PID 11483) reaching to 161MB.
GC.stat
(captured via rbtrace
gem) look like (pay close attention to attention to GC count
)
rbtrace -p 11843 -e '[Time.now,Process.pid,GC.stat]'
[Time.now,Process.pid,GC.stat]
=> [2016-07-27 13:50:28 +0530, 11843,
{
"count": 7,
"heap_allocated_pages": 74,
"heap_sorted_length": 75,
"heap_allocatable_pages": 0,
"heap_available_slots": 30162,
"heap_live_slots": 11479,
"heap_free_slots": 18594,
"heap_final_slots": 89,
"heap_marked_slots": 120,
"heap_swept_slots": 18847,
"heap_eden_pages": 74,
"heap_tomb_pages": 0,
"total_allocated_pages": 74,
"total_freed_pages": 0,
"total_allocated_objects": 66182,
"total_freed_objects": 54614,
"malloc_increase_bytes": 8368,
"malloc_increase_bytes_limit": 33554432,
"minor_gc_count": 4,
"major_gc_count": 3,
"remembered_wb_unprotected_objects": 0,
"remembered_wb_unprotected_objects_limit": 278,
"old_objects": 14,
"old_objects_limit": 10766,
"oldmalloc_increase_bytes": 198674592,
"oldmalloc_increase_bytes_limit": 20132659
}]
*** detached from process 11843
GC count => 7
Approximately 25 minutes later. Memory has drop down to 6MB but GC count is still 7.
[Time.now,Process.pid,GC.stat]
=> [2016-07-27 14:16:02 +0530, 11843,
{
"count": 7,
"heap_allocated_pages": 74,
"heap_sorted_length": 75,
"heap_allocatable_pages": 0,
"heap_available_slots": 30162,
"heap_live_slots": 11581,
"heap_free_slots": 18581,
"heap_final_slots": 0,
"heap_marked_slots": 120,
"heap_swept_slots": 18936,
"heap_eden_pages": 74,
"heap_tomb_pages": 0,
"total_allocated_pages": 74,
"total_freed_pages": 0,
"total_allocated_objects": 66284,
"total_freed_objects": 54703,
"malloc_increase_bytes": 3248,
"malloc_increase_bytes_limit": 33554432,
"minor_gc_count": 4,
"major_gc_count": 3,
"remembered_wb_unprotected_objects": 0,
"remembered_wb_unprotected_objects_limit": 278,
"old_objects": 14,
"old_objects_limit": 10766,
"oldmalloc_increase_bytes": 198663520,
"oldmalloc_increase_bytes_limit": 20132659
}]
Question: I was under the impression that Ruby Release memory whenever GC is triggered. But clearly that not the case over here.
Anybody can provide a detail on how (as in who triggered the memory releases surely its not GC.) the memory is released back to OS.
OS: OS X version 10.11.12
Upvotes: 4
Views: 1615
Reputation: 34338
You are correct, it's not GC that changed the physical memory requirements, it's the OS kernel.
You need to look at the VIRT
column, not the RES
column. As you can see VIRT
stays exactly the same.
RES
is physical (resident) memory, VIRT
is virtual (allocated, but currently unused) memory.
When the process sleeps it's not using its memory or doing anything, so the OS memory manager decides to swap out part of the physical memory and move it into virtual space.
Why keep an idle process hogging physical memory for no reason? So the OS is smart, and swaps out as much unused physical memory as possible, that's why you see a reduction in RES
.
I suspect you would see the same effect even without array = nil
, by just sleeping long enough. Once you stop sleeping and access something in the array, then RES
will jump back up again.
You can read some more discussion through these:
What is RSS and VSZ in Linux memory management
http://www.darkcoding.net/software/resident-and-virtual-memory-on-linux-a-short-example/
What's the difference between "virtual memory" and "swap space"?
http://www.tldp.org/LDP/tlk/mm/memory.html
Upvotes: 4