Рассмотрим приведенный ниже код:
from threading import Thread
import numpy as np
import gc
class TargetClass:
def __init__(self):
self.lt = []
def execute(self):
print("list started")
for idx in range(10):
self.lt.append(np.linspace(0,100,1000000))
print("list completed")
self._flush()
def _flush(self):
self.lt.clear()
self.lt = None
# gc.collect()
def main():
print("starting run")
threads = []
objs = []
for idx in range(20):
obj = TargetClass()
objs.append(obj)
th = Thread(target=obj.execute)
threads.append(th)
for th in threads:
th.start()
for th in threads:
th.join()
for obj in objs:
del obj
threads.clear()
print("run end")
if __name__ == "__main__":
for idx in range(5):
main()
После того, как основной метод будет выполнен 5 раз, ОЗУ ЦП, используемое процессом, будет где-то между 850 МБ - 1,1 ГБ (меняется в разных циклах). Я проверяю эту память на системном мониторе Ubuntu, добавляя pdb
после вызова main
. Однако одна вещь, которая здесь интересна, заключается в том, что если я запускаю операторы метода execute
один за другим в терминале python, а затем операторы из метода _flush
, то память процесса python составляет около 16 МБ. .
У меня есть два вопроса, которые связаны между собой:
- Почему так много памяти используется процессом даже после очистки списков?
- Как уменьшить это потребление памяти? (это основной мотив)
Этот скрипт является очень маленькой частью моего приложения, где я использую очереди для передачи данных между несколькими потоками. Размер каждых данных в очередях составляет около 8 МБ. После обработки целых данных и удаления ссылок (насколько мне известно) использование памяти процессом не сокращается полностью. Я не могу завершить процесс и повторно запустить его, так как загрузка зависимостей занимает время.
Python 3.6.8, NumPy 1.17.4
Редактировать 1 : Если список заполнен плавающими числами вместо NumPy объектов массива, тогда память очищается до 16 МБ после очистки списков.