Ako mi Django "ujedalo" pamäť

V Djang-u mám zadefinovanú jednu dlhotrvajúcu úlohu ktorá beží na pozadí aj niekoľko hodín. Skript som testoval lokálne v odlaďovacom režime, ale keď som monitoroval skript či pracuje správne, tak som zistil že skript "ujedal" pomaličky pamäť. Po niekoľkých hodinách už zaberal cez 50% pamäte, to bolo nemyslitelné aby tento skript spotreboval toľko prostriedkov. Samozrejme som mal podozrenie na "memory leak", ale stým som sa stretával v iných jazykoch ako napr C++ v Pythone som sa s týmto problémom ešte nestretol (naivne som si myslel že sa ani nestretnem).

Tak som začal pomaly pátrať ako "memory leakom" v Pythone predísť. Začal som s jednoduchým mazaním premenných del premmenna, ale to nepomohlo. Tak som ešte pre istotu nastavoval hodnotu premennej na None (premmenna = None), ale ani to nepomohlo. Tak som skúsil manuálne volať "garbage collector" ale ani to nepomohlo, program stále spotrebovával viac a viac pamäte.

Nechcel som sa moc púšťať do "profilovacích" nástrojov, pomocou ktorých sa dá monitorovať spotreba pamäte v Python programoch. Ale nakoniec už som nevedel ako ďalej, tak som sa chtiac - nechtiach pustil do profilovania.

# detekcia memory leak-u

import tracemalloc  
tracemalloc.start()

s1 = tracemalloc.take_snapshot()  
... long task ...
s2 = tracemalloc.take_snapshot()

top_stats = s2.compare_to(s1, 'lineno')  
for stat in top_stats[:10]:  
    print(stat)

V podstate som zistil že mi pamäť "vyjedajú" Django operácie pracujúce s databázou. Tak problém som síce identifikoval, ale riešenie nebolo zrejmé. Odlaďovať operácie frameworku Django sa mi určite nechcelo. Nakoniec som narazil na nenápadný komentár na stackowerflow Django - huge memory usage on “for” with QuerySet.

Additionally, make sure you have DEBUG=False in your settings.py otherwise it remembers every SQL query you execute (eating RAM).

Po troch dňoch pátrania, testovania, profilovania bol problém vyriešený pridaním riadku DEBUG=False :)

Show Comments