Утечка памяти в matplotlib python — постоянное небольшое увеличение «цикла for»

#python #pandas #matplotlib #memory-leaks

#python #pandas #matplotlib #утечки памяти

Вопрос:

Я страдаю от утечки памяти в моем «цикле for (более 1100 циклов)» для создания карт. Я не могу определить, что так сильно требует памяти во время циклов. Когда я проверил, что может помочь — большинство подсказок commons должны были использовать:

  • plt.clf()
  • gc.collect()

ни то, ни другое не помогло.

Когда я проверяю циклы psutil.Process(os.getpid()).memory_info().rss / 1024 ** 2 на использование памяти, оно постоянно увеличивается на 31 МБ на цикл, даже если циклы не всегда одинаковы (существует 4 возможности / способа создания карт). objgraph Я попытался определить, что накапливается в памяти, но я не могу точно определить, что происходит. Вот вывод из (objgraph.show_growth()) :

 dict                          20565        49
method                         1034        26
list                           6886        21
weakref                       11206        20
tuple                         11657        19
cell                           6584        18
function                      22611        17
builtin_function_or_method     5268        13
WeakMethod                      232         7
Bbox                            223         6
 

Вот пример кода (один из 4), который я использую для создания карт:

 def plot_map_lin (boundry, colm_var, shp, code_name):
   name_val = []
   vmin = 9999999
   vmax = 0
   for row in range(lencodes):
       cell = data.iloc[row][colm_var]
       name_val.append(float(cell)   abs(boundry[0]))
       if float(cell) > vmax:
           vmax = int(cell)
       elif float(cell) < vmin:
           vmin = int(cell)
   gdfdict[colm_var] = name_val
   df = pd.DataFrame(gdfdict)
   map_df = gpd.read_file(shp)
   map_df['KOD'] = map_df['KOD'].astype(int)
   merge = map_df.merge(df, left_on = 'KOD', right_on = 'Kod')
   fig, ax = plt.subplots(1, figsize = (40, 20))
   cmap = mpl.cm.YlGn
   norm = mpl.colors.Normalize(vmin = vmin, vmax = vmax)
   cb = plt.colorbar(mpl.cm.ScalarMappable(norm = norm, cmap = cmap), orientation = 'vertical', format = mpl.ticker.FuncFormatter(format_ticks))
   cb.set_label(label = label_name(code_name), size = 20)
   merge.plot(column = colm_var, cmap = map_color, linewidth = 0.2, ax = ax, edgecolor = '0.5')
   ax.set_title(map_name(colm_var), fontdict = {'fontsize': '35', 'fontweight' : '10'})
   ax.axis('off')
   name_of_map = "Linear"   colm_var   ".png"
   plt.savefig(path_script   "/Mapy/"   name_of_map, dpi=100)
   plt.clf()
   gc.collect()
   print(objgraph.show_growth())
   print(psutil.Process(os.getpid()).memory_info().rss / 1024 ** 2)
 

Кто-нибудь знает, что не так, и, возможно, как это исправить?

Спасибо

Комментарии:

1. Действительно трудно сказать без вашего кода. Вы пробовали не отображать фигуру, но оставляли остальную часть цикла неизменной? т. Е. прокомментируйте все после fig, ax = ... и посмотрите, сохраняется ли утечка памяти? Например, в приведенном выше примере у вас есть куча глобальных переменных, которые, насколько я могу судить, могут легко увеличиваться в памяти в зависимости от того, насколько они велики data .

2. Привет, я попробовал комментировать, как вы предлагали — 99% увеличения памяти и утечка вызваны этой строкой plt.savefig(path_script "/Mapy/" name_of_map, dpi=100) , но я не могу понять, почему. Когда у меня есть plt.clf() , gc.collect() а теперь и plt.close('all') после plt.savefig , я подумал, что он должен очистить память от fig, но каким-то образом он застрял в нем.

3. Я думаю, что застревание в памяти каким-то образом вызвано тем фактом, что в нем есть два графика, fig, ax = plt.subplots(1, figsize = (40, 20)) и в конце он стирает только один из них. Не уверен в этом, и я даже не знаю, как это выяснить, потому что «fig» и «ax» недоступны после цикла.

4. Это действительно трудно сказать без всего вашего кода. Предлагаю вам попытаться создать минимально воспроизводимый пример, и это либо сделает вещи очевидными, либо даст нам что-то для работы. Я подозреваю, что вы не закрываете все свои цифры.

Ответ №1:

Вы можете попробовать как plt.clf(), так и plt.cla()(очищая обе фигуры и оси соответственно).Если это не работает быстро (возможно, немного затратно по времени выполнения), это запустить вашу функцию как другой процесс, который умрет и очистит всю память в случае утечки памяти.

Комментарии:

1. plt.cla() также не имеет никакого эффекта plt.close() , plt.close('all) , и т.д. fig.clf() Однако я обнаружил, что «застрявшая» память пропорционально равна размеру рисунка fig, ax = plt.subplots(1, figsize = (40, 20)) — когда я меняю 40, 20 на 20, 10 и, таким образом, уменьшаю fig в 4 раза, «застрявшая» память также в 4 раза меньше. Но пока никакого дальнейшего прогресса.