Однако память не освобождается сразу — она освобождается только после сборки мусора поколения 2.
Мой первый подход
Я попробовал вызвать:
Код: Выделить всё
gc.collect()
malloc_trim(0)
Это работает, но документация Python предупреждает, что:
Эффект вызова gc.collect(), когда интерпретатор уже выполняет сбор, не определен.
Таким образом, этот подход потенциально может вызвать неопределенное поведение, что делает его небезопасным для использования в рабочей среде.
/>Мой второй подход
Вместо этого я попробовал дождаться естественной коллекции gen=2, а затем вызвать malloc_trim.
Я сделал это, зарегистрировав обратный вызов GC:
Код: Выделить всё
def gc_trim_callback(phase, info):
if phase == "stop" and info["generation"] == 2:
malloc_trim(0)
gc.callbacks.remove(gc_trim_callback)
gc.callbacks.append(gc_trim_callback)
Проблема
Проблема в том, что иногда после завершения тяжелой функции процесс простаивает до того, как произойдет сбор данных поколения 2.
Если пользователь не выполняет никаких дальнейших действий, процесс может простаивать в течение часов, дней или даже месяцев, сохраняя неиспользованную память на неопределенный срок. Это неприемлемо для моего варианта использования.
Я придумал два очень плохих решения для запуска коллекции поколения 2 «естественным образом»:
- Регулировка порога GC с помощью gc.set_threshold(), чтобы коллекции поколения 2 происходили чаще, — но это кажется хакерским и может отрицательно повлиять на производительность.
- Создание большого количества искусственных циклов ссылки после возврата функции, а затем освобождая их для запуска коллекции gen2 — тоже очень хакерски и неэффективно.
Подробнее здесь: https://stackoverflow.com/questions/798 ... forcing-gc
Мобильная версия