Во-первых, DEBUG = False
в settings.py, так что нет, connections['default'].queries
не увеличивается и не увеличивается, пока не израсходует всю память.
Давайте начнем с того, что я загрузил таблицу User
из django.contrib.auth.models.User
для 10000 пользователей (каждый с именем 'test #', где # - это число от 1 до 10000).
Вот вид:
from django.contrib.auth.models import User
from django.http import HttpResponse
import time
def leak(request):
print "loading users"
users = []
users += list(User.objects.all())
users += list(User.objects.all())
users += list(User.objects.all())
users += list(User.objects.all())
users += list(User.objects.all())
users += list(User.objects.all())
users += list(User.objects.all())
users += list(User.objects.all())
users += list(User.objects.all())
users += list(User.objects.all())
users += list(User.objects.all())
users += list(User.objects.all())
users += list(User.objects.all())
users += list(User.objects.all())
users += list(User.objects.all())
users += list(User.objects.all())
users += list(User.objects.all())
print "sleeping"
time.sleep(10)
return HttpResponse('')
Я прикрепил приведенное выше представление к URL-адресу /leak/
и запустил сервер разработки (с DEBUG = False, и я проверил, и он не имеет ничего для работы с сервером разработки против другие случаи).
После запуска:
% curl http://localhost:8000/leak/
Объем памяти процесса runserver увеличивается примерно до размера, видимого из вывода ps aux
ниже, а затем остается на этом уровне.
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
dlamotte 25694 11.5 34.8 861384 705668 pts/3 Sl+ 19:11 2:52 /home/dlamotte/tmp/django-mem-leak/env/bin/python ./manage.py runserver
Тогда выполнение вышеуказанной команды curl
, приведенной выше, похоже, не увеличивает использование памяти экземпляром (что я ожидал от настоящей утечки памяти?), Это должно быть повторное использование памяти? Однако я чувствую, что здесь что-то не так, что память не высвобождается в систему (однако я понимаю, что производительность может быть выше, если python НЕ освобождает память).
После этого я наивно попытался выяснить, выпустит ли python большие куски памяти, которые он выделил. Поэтому я пытаюсь сделать следующее из сессии Python:
>>> a = ''
>>> a += 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' * 10000000
>>> del a
Память выделяется в строке a += ...
, как и ожидалось, но когда происходит del a
, память освобождается. Почему поведение отличается для наборов запросов django? Это то, что Django собирается сделать? Есть ли способ изменить это поведение?
Я буквально потратил 2 дня на отладку этого поведения, не зная, куда идти дальше (я научился использовать гуппи и objgraph, которые, кажется, не указывают ни на что интересное, что я могу выяснить).
ОБНОВЛЕНИЕ: Это может быть просто управление памятью Python на работе и не иметь никакого отношения к Django (рекомендуется в списке рассылки django-users), но я хотел бы получить подтверждение, каким-то образом повторив это в python за пределами Джанго.
ОБНОВЛЕНИЕ: Использование Python версии 2.6.5