Opened 3 hours ago

Last modified 3 hours ago

#36674 new Cleanup/optimization

select_related() leaks memory

Reported by: Jacob Walls Owned by:
Component: Database layer (models, ORM) Version: dev
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Calls to select_related() create nested functions that aren't cleaned up until garbage collection runs:

Borrowed testing strategy from #34865:

  • tests/select_related/tests.py

    diff --git a/tests/select_related/tests.py b/tests/select_related/tests.py
    index 41ed350cf3..252e884d7a 100644
    a b class SelectRelatedTests(TestCase):  
    242242            FETCH_PEERS,
    243243        )
    244244
     245    def test_memory_leak(self):
     246        # todo: factor out a test util
     247        import gc
     248   
     249        # Schedule the restore of the garbage collection settings.
     250        self.addCleanup(gc.set_debug, 0)
     251        self.addCleanup(gc.enable)
     252
     253        # Disable automatic garbage collection to control when it's triggered,
     254        # then run a full collection cycle to ensure `gc.garbage` is empty.
     255        gc.disable()
     256        gc.collect()
     257
     258        # The garbage list isn't automatically populated to avoid CPU overhead,
     259        # so debugging needs to be enabled to track all unreachable items and
     260        # have them stored in `gc.garbage`.
     261        gc.set_debug(gc.DEBUG_SAVEALL)
     262
     263        list(Species.objects.select_related("genus"))
     264
     265        # Enforce garbage collection to populate `gc.garbage` for inspection.
     266        gc.collect()
     267        self.assertEqual(gc.garbage, [])
     268
    245269
    246270class SelectRelatedValidationTests(SimpleTestCase):
    247271    """

Gives:

AssertionError: Lists differ: [<cell at 0x10630c940: function object at [148 chars]040>] != []

First list contains 3 additional elements.
First extra element 0:
<cell at 0x10630c940: function object at 0x1079b8040>

+ []
- [<cell at 0x10630c940: function object at 0x1079b8040>,
-  (<cell at 0x10630c940: function object at 0x1079b8040>,),
-  <function SQLCompiler.get_select.<locals>.get_select_from_parent at 0x1079b8040>]

At a glance, it looks like we can lift get_select_from_parent to a class method or all the way to module-level without a loss of functionality to address this.

Change History (1)

comment:1 by Simon Charette, 3 hours ago

Triage Stage: UnreviewedAccepted

Good catch, looks like it could even be a staticmethod since it only cares about klass_info.

Note: See TracTickets for help on using tickets.
Back to Top