Project

General

Profile

Actions

Bug #18014

closed

Memory leak in GC when using Ractors

Added by peterzhu2118 (Peter Zhu) almost 3 years ago. Updated almost 3 years ago.

Status:
Closed
Assignee:
-
Target version:
-
[ruby-core:104443]

Description

GitHub PR: https://github.com/ruby/ruby/pull/4613

When a Ractor is removed, the freelist in the Ractor cache is not returned to the GC, leaving the freelist permanently lost.

The following script demonstrates the issue. It iterates 2000 times, in each iteration it simply creates a new Ractor that creates a new object. It stores the objects in an array in the main thread to prevent the object from being GC'd. This is important as if the object is GC'd the heap page will be freed if the whole page is empty.

arr = []

2000.times do
  # Start new Ractor that creates a new object
  arr << Ractor.new { Object.new }.take
  puts GC.stat(:heap_allocated_pages)
end

We can now graph the output from master and the branch with the patch.

We can see that the Ractor implementation creates heap pages linearly with the number of iterations. On my machine, this script on master uses about 43MB of memory while the patched version uses 13MB.

This is because when a new heap page is created (with 409 empty slots), the Ractor uses the page to allocate a single object, and leaks the remaining slots (408 slots).

Patch

The patch recycles the freelist when the Ractor is destroyed, preventing a memory leak from occurring.

An assertion has been added after gc_page_sweep to verify that the freelist length is equal to the number of free slots in the page.

Actions #1

Updated by peterzhu2118 (Peter Zhu) almost 3 years ago

  • Backport changed from 2.6: UNKNOWN, 2.7: UNKNOWN, 3.0: UNKNOWN to 2.6: DONTNEED, 2.7: DONTNEED, 3.0: REQUIRED
Actions #2

Updated by peterzhu2118 (Peter Zhu) almost 3 years ago

  • Status changed from Open to Closed

Applied in changeset git|119697f61e2b2b157816a8aa33aada5863959900.


[Bug #18014] Fix rb_gc_force_recycle unmark before sweep

If we force recycle an object before the page is swept, we should clear
it in the mark bitmap. If we don't clear it in the bitmap, then during
sweeping we won't account for this free slot so the free_slots count
of the page will be incorrect.

Updated by nagachika (Tomoyuki Chikanaga) almost 3 years ago

Backporting 4a627dbdfd1165022fa9e716ba845e937b03773d conflicts since ruby_3_0 does not include T_PAYLOAD.
I have created the patch for ruby_3_0 to partially backport 119697f61e2b2b157816a8aa33aada5863959900 and 4a627dbdfd1165022fa9e716ba845e937b03773d.

https://github.com/nagachika/ruby/commit/3c3db50a7e872b8ad32b151325f02a51dc82a3ce

I have confirmed that the memory leak was fixed with the patch using the example script in the description.

Please review the patch.

Updated by nagachika (Tomoyuki Chikanaga) almost 3 years ago

Thank you for reviewing. I will commit the patch soon.

Updated by nagachika (Tomoyuki Chikanaga) almost 3 years ago

  • Backport changed from 2.6: DONTNEED, 2.7: DONTNEED, 3.0: REQUIRED to 2.6: DONTNEED, 2.7: DONTNEED, 3.0: DONE

ruby_3_0 a215c6d0448764131cbbb48b476dc698b51c2273 merged revision(s) 119697f61e2b2b157816a8aa33aada5863959900,4a627dbdfd1165022fa9e716ba845e937b03773d.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0