Почему память не выделяется в систему после больших запросов (или серии запросов) в django?

Во-первых, DEBUG = False в settings.py, поэтому нет, connections['default'].queries не растут и не растут, пока не используют всю память.

Давайте начнем с того, что я загрузил таблицу User из django.contrib.auth.models.User с 10000 пользователями (каждый из них назвал «test #», где # – число от 1 до 10000).

  • Как предотвратить утечку памяти при загрузке больших файлов pickle в цикл for?
  • Профилирование / мониторинг памяти (python) в Google AppEngine
  • Python - работа с утечками памяти
  • Возможно ли иметь реальную утечку памяти в Python из-за вашего кода?
  • Огромная утечка памяти при повторных вызовах os.path.isdir?
  • Выгрузить модуль в Python
  • Вот взгляд:

     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('') 

    Я прикрепил вид выше к /leak/ url и запустил сервер разработки (с DEBUG = False, и я протестировал его, и он не имеет никакого отношения к запуску сервера разработки и других экземпляров).

    После запуска:

     % curl http://localhost:8000/leak/ 

    Память процесса сервера-хранителя растет примерно до размера, указанного ниже, а затем остается на этом уровне.

     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 отличается от поведения? Это что-то, что джанго намеревается сделать? Есть ли способ изменить это поведение?

    Я буквально провел 2 дня, отлаживая это поведение, не представляя, куда идти дальше (я научился использовать guppy AND objgraph, который, похоже, не указывает на что-либо интересное, что я могу выяснить).

    UPDATE: это может быть просто управление памятью python на работе и не имеет ничего общего с Django (предлагается в списке рассылки django-users), но я бы хотел подтвердить, как-то реплицируя это в python за пределами Django.

    ОБНОВЛЕНИЕ: Использование версии python 2.6.5

  • Как написать тесты для форм в Django?
  • Django views.py. Версия SQL. Присоединение к Multi Table Query
  • Django unique = True не работает
  • Как получить доступ к объекту запроса или любой другой переменной в методе clean () формы?
  • Python Django: нет модуля с именем security
  • Python MySQLDB: получить результат fetchall в списке
  • 2 Solutions collect form web for “Почему память не выделяется в систему после больших запросов (или серии запросов) в django?”

    Я решил переместить свои комментарии в ответ, чтобы сделать вещи более ясными.

    Начиная с Python 2.5, распределение памяти CPython отслеживает использование внутренней памяти небольшим распределителем объектов и пытается вернуть полностью свободные арены в базовую ОС. Это работает большую часть времени, но тот факт, что объекты не могут перемещаться в памяти, означает, что фрагментация может быть серьезной проблемой.

    Попробуйте следующий эксперимент (я использовал 3.2, но 2.5+ должен быть похож, если вы используете xrange):

     # Create the big lists in advance to avoid skewing the memory counts seq1 = [None] * 10**6 # Big list of references to None seq2 = seq1[::10] # Create and reference a lot of smaller lists seq1[:] = [[] for x in range(10**6)] # References all the new lists seq2[:] = seq1[::10] # Grab a second reference to 10% of the new lists # Memory fragmentation in action seq1[:] = [None] * 10**6 # 90% of the lists are no longer referenced here seq2[:] = seq1[::10] # But memory freed only after last 10% are dropped 

    Обратите внимание, что даже если вы отбросите ссылки на seq1 и seq2 , seq2 выше последовательность, скорее всего, оставит процесс Python большим количеством дополнительной памяти.

    Когда люди говорят о PyPy, используя меньше памяти, чем CPython, это большая часть того, о чем они говорят. Поскольку PyPy не использует ссылки прямого указателя под капотом, он может использовать уплотняющий GC, тем самым избегая значительной части проблемы фрагментации и более надежно возвращая память в ОС.

    Многие приложения, языковые среды выполнения и, возможно, даже некоторые системные распределители памяти будут хранить освобожденную память на месте как можно дольше, с целью ее повторного использования, исключительно для повышения производительности. В сложной системе, такой как Django, может быть любое количество расширений, возможно, реализованных на C, которые демонстрируют это поведение, или это может быть Python с каким-то пулом памяти или ленивой сборкой мусора.

    Это может быть даже основная реализация malloc, выполняющая это, или ваша операционная система, сохраняющая определенный объем памяти, выделенный для вашего процесса, даже если этот процесс явно не использует его. Не цитируйте меня на этом, хотя это было давно, так как я изучал такие вещи.

    В целом, хотя, если повторить процесс выделения после первоначального выделения и dealloc не удваивает объем используемой памяти, то, что вы видите, не является утечкой памяти, а пулом памяти. Вероятно, это будет проблемой, если у вас много процессов, которые требуют ограниченного объема памяти на этой машине.

    Python - лучший язык программирования в мире.