Fix memory leak in GC when using Ractors #4613
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Redmine ticket: https://bugs.ruby-lang.org/issues/18014
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.
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.