-
Type: Bug
-
Resolution: Fixed
-
Priority: Critical - P2
-
Affects Version/s: 9.0.2
-
Component/s: None
-
None
-
Ruby Drivers
-
Not Needed
-
Copied from PR - https://github.com/mongodb/mongoid/pull/5878
The issue
I found the memory leak inside Threaded class, when saving documents within transaction: session object is retained forever inside thread-local variable.
Explanation
Mongoid uses thread-local variables to temporarily hold modified_documents until transaction is committed.
The [mongoid]:modified-documents contains a hash with session as key and Set of documents as value.
During transaction commit phase, the Mongoid::Threaded::clear_modified_documents is called, which clears documents from the set, however, the hash inside [mongoid]:modified-documents still contains a session object as a key.
This session object is then persists in memory, even after the session was finished by the Mongoid::Threaded::clear_session call.
Testing
I used the following code to reproduce the issue:
require_relative 'spec_helper' require 'memory_profiler' describe "Mongoid test" do let(:model) do Class.new do include Mongoid::Document store_in collection: 'tests' field :name, type: String end end context 'memory leak test' do it 'store in transaction' do run_memory_profiling do model.transaction do model.create!(name: 'test') end end end end def run_memory_profiling(&block) # Warmup yield report = MemoryProfiler.report do 2000.times(&block) GC.start(full_mark: true, immediate_sweep: true) end p "Total retained: #{report.total_retained_memsize / 1024} KB (#{report.total_retained} objects). " end end
Initial results:
Total retained: 3430 KB (36053 objects).
Report shows a number of retained objects, which corresponds to 2000 iterations of test.
Results after modification:
Total retained: 6 KB (61 objects).