Найти - Пользователи
Полная версия: memory leak в простом скрипте, но с большим объемом данных.
Начало » Python для экспертов » memory leak в простом скрипте, но с большим объемом данных.
1
VadimK
Есть скрипт с Django на простой логике:

 def task(order_id):
    order = Orders.objects.get(pk=order_id)
    cache, created = OrderIndexer.objects.get_or_create(order=order_id)
    cache.name = order.country_from_name
    # и так далее
    cache.save()
    
    del order
    del cache
    
rs = Orders.objects.filter()
for row in rs:
    task(row.id)
    del row

Грубо говоря вытягиваем из одной таблицы данные, агрегируем их в нужный вид и записываем в другую. Записей много. За время работы скрипт съедает более 1 гига оперативки. Попытки принудительно удалять объекты ничего не дают. Видно как постепенно размер потребляемой памяти растет, а по окончанию освобождается.

Скрипт вызывается из консоли, т.е. поведение прекрасно видно.
FishHook
VadimK
первым делом попробуйте принудительно коммитить транзакцию
во-вторых, если вы экономите пямять, то зачем делаете select *? Используйте only и defer, например,
 order = Orders.objects.filter(pk=order_id).only("name")[0]
в-третьих, старайтесь комбинировать запросы, типа
 cache = OrderIndexer.objects.filter(order__in=Orders.objects.filter(pk=order_id).only("id"))
это уменьшит количество запросов, и создаваемых объектов.

VadimK
Попытки принудительно удалять объекты ничего не дают.
вы их не удаляете принудительно, вы их помечаете для удаления для сборщика мусора, сам сборщик никуда не девается. Попробуйте его отключить

ну и гонять гигабайты данных по сети, только чтобы использовать всю “мощь” идиотского джанговского ОРМ - ну так себе идея. Вы же понимаете, что скопировать миллион значений из одной таблицы в другую можно миллионом запросов, а можно одним? Вы выбрали путь миллиона запросов, и удивляетесь, что отъело целый гигабайт. Сделайте один запрос на чистом SQL и у вас отъест 0 байт.
VadimK
Это не весь скрипт, там десятки полей включая текстовые. Данные агрегируются для поиска, формируются json объекты для последующего использования и т.п. Это ни каким одним запросом не сделать.


Если правильно понимаю, внутри task() формируются объекты cache, order - далее помечаются как удаленные и отправляются в память. Следующим вызовом формируются новые, снова помечаются и так далее по циклу.

gc.collect() в цикле в общем то решило проблему, рост минимальный
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB