-
-
Notifications
You must be signed in to change notification settings - Fork 33.3k
Fixed #36701 -- Fixed memory leak in ModelState reference cycles #20380
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Fixed #36701 -- Fixed memory leak in ModelState reference cycles #20380
Conversation
cbaf05e to
4c184a7
Compare
jacobtylerwalls
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks 👍
| except AttributeError: | ||
| pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need the except?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for explaining -- in that case these lines are reachable, so we need a test to cover them.
tests/model_regress/test_state.py
Outdated
| self.addCleanup(gc.set_debug, gc.get_debug()) | ||
| gc.set_debug(gc.DEBUG_SAVEALL) | ||
|
|
||
| gc.collect() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use the garbage_collect() helper from django.test.utils.
tests/model_regress/test_state.py
Outdated
| gc.set_debug(gc.DEBUG_SAVEALL) | ||
|
|
||
| gc.collect() | ||
| del gc.garbage[:] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need this?
tests/model_regress/test_state.py
Outdated
| """ | ||
| Ensure OneToOneField intermediate state does not create reference | ||
| cycles during model initialization. | ||
| """ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| """ | |
| Ensure OneToOneField intermediate state does not create reference | |
| cycles during model initialization. | |
| """ |
Thanks for the method name change. Now we can lose the docstring (we avoid "Ensure ..." preambles anyway.)
|
|
||
| leaked = [obj for obj in gc.garbage if id(obj) == p_id] | ||
|
|
||
| self.assertEqual(leaked, []) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After this test I get this warning:
Exception ignored in GC shutdown:
ResourceWarning: gc: 7995 uncollectable objects at shutdown; use gc.set_debug(gc.DEBUG_UNCOLLECTABLE) to list themThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, thanks very much for explaining. Now we need to register this as a cleanup earlier (right after garbage_collect, with self.addCleanup) because if the assertion fails for some reason I get the warning again.
4c184a7 to
126f444
Compare
|
@jacobtylerwalls I tried to write tests using Also removed the |
126f444 to
78c2504
Compare
|
@jacobtylerwalls For the |
📊 Coverage Report for Changed FilesNote: Missing lines are warnings only. Some lines may not be covered by SQLite tests as they are database-specific. For more information about code coverage on pull requests, see the contributing documentation. |
jacobtylerwalls
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the updates 👍
| except AttributeError: | ||
| pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for explaining -- in that case these lines are reachable, so we need a test to cover them.
|
|
||
| leaked = [obj for obj in gc.garbage if id(obj) == p_id] | ||
|
|
||
| self.assertEqual(leaked, []) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, thanks very much for explaining. Now we need to register this as a cleanup earlier (right after garbage_collect, with self.addCleanup) because if the assertion fails for some reason I get the warning again.
Trac ticket number
ticket-36701
Branch description
This PR addresses ticket #36701 regarding memory leaks caused by reference cycles in
ModelStateI implemented a
__del__method onModelStateto explicitly clearself.fields_cache.I added a regression test (
tests/model_state/test_memory_leak.py) that:OneToOneFieldcycle.gc.collect().weakref).I also verified this locally with a reproduction script generating 50,000 cyclic objects. Without the fix, memory usage balloons. With the fix,
gc.collect()successfully reclaims the objects.Checklist
mainbranch.