2012-05-15 3 views
11

Я сталкиваюсь с проблемой утечек памяти, используя pandas библиотека в python. Я создаю объекты pandas.dataframe в моем классе, и у меня есть метод, который меняет размер данных в соответствии с моими условиями. После изменения размера фрейма и создания нового объекта pandas я переписываю оригинальный pandas.dataframe в моем классе. Но использование памяти очень велико даже после значительного сокращения начальной таблицы. Некоторый код для короткого примера (я не пишу менеджер процессов, менеджер задач см):Pandas: где утечка памяти здесь?

import time, string, pandas, numpy, gc 
class temp_class(): 

    def __init__(self, nrow = 1000000, ncol = 4, timetest = 5): 

     self.nrow = nrow 
     self.ncol = ncol 
     self.timetest = timetest 

    def createDataFrame(self): 

     print('Check memory before dataframe creating') 
     time.sleep(self.timetest) 
     self.df = pandas.DataFrame(numpy.random.randn(self.nrow, self.ncol), 
      index = numpy.random.randn(self.nrow), columns = list(string.letters[0:self.ncol])) 
     print('Check memory after dataFrame creating') 
     time.sleep(self.timetest) 

    def changeSize(self, from_ = 0, to_ = 100): 

     df_new = self.df[from_:to_].copy() 
     print('Check memory after changing size') 
     time.sleep(self.timetest) 

     print('Check memory after deleting initial pandas object') 
     del self.df 
     time.sleep(self.timetest) 

     print('Check memory after deleting copy of reduced pandas object') 
     del df_new 
     gc.collect() 
     time.sleep(self.timetest) 

if __name__== '__main__': 

    a = temp_class() 
    a.createDataFrame() 
    a.changeSize() 
  • Перед dataframe создания у меня ок. 15 Мб использования памяти

  • После создания - 67MB

  • После изменения размера - 67 Мб

  • После удаления оригинального dataframe - 35MB

  • После удаления уменьшенной таблицы - 31 Мб.

16 мб?

Я использую python 2.7.2 (x32) для Windows 7 (x64) machine, pandas. версия - 0.7.3. NumPy. версия является 1.6.1

+0

Так работает распределение памяти Python. Вероятно, утечки памяти нет. – jozzas

ответ

26

Пару вещей укажут:

  1. В «Проверка памяти после изменения размера», вы не удалили оригинальный DataFrame еще, так что это будет использовать строго больше памяти

  2. Интерпретатор Python немного жадничает о сохранении памяти ОС.

Я заглянул в это и заверил вас, что панды не проливают память. Я использую memory_profiler пакет (http://pypi.python.org/pypi/memory_profiler):

import time, string, pandas, numpy, gc 
from memory_profiler import LineProfiler, show_results 
import memory_profiler as mprof 

prof = LineProfiler() 

@prof 
def test(nrow=1000000, ncol = 4, timetest = 5): 
    from_ = nrow // 10 
    to_ = 9 * nrow // 10 
    df = pandas.DataFrame(numpy.random.randn(nrow, ncol), 
          index = numpy.random.randn(nrow), 
          columns = list(string.letters[0:ncol])) 
    df_new = df[from_:to_].copy() 
    del df 
    del df_new 
    gc.collect() 

test() 
# for _ in xrange(10): 
#  print mprof.memory_usage() 

show_results(prof) 

А вот выход

10:15 ~/tmp $ python profmem.py 
Line # Mem usage Increment Line Contents 
============================================== 
    7       @prof 
    8  28.77 MB 0.00 MB def test(nrow=1000000, ncol = 4, timetest = 5): 
    9  28.77 MB 0.00 MB  from_ = nrow // 10 
    10  28.77 MB 0.00 MB  to_ = 9 * nrow // 10 
    11  59.19 MB 30.42 MB  df = pandas.DataFrame(numpy.random.randn(nrow, ncol), 
    12  66.77 MB 7.58 MB        index = numpy.random.randn(nrow), 
    13  90.46 MB 23.70 MB        columns = list(string.letters[0:ncol])) 
    14 114.96 MB 24.49 MB  df_new = df[from_:to_].copy() 
    15 114.96 MB 0.00 MB  del df 
    16  90.54 MB -24.42 MB  del df_new 
    17  52.39 MB -38.15 MB  gc.collect() 

Так на самом деле, есть больше памяти используется чем когда мы начали. Но это утечка?

for _ in xrange(20): 
    test() 
    print mprof.memory_usage() 

И выход:

10:19 ~/tmp $ python profmem.py 
[52.3984375] 
[122.59375] 
[122.59375] 
[122.59375] 
[122.59375] 
[122.59375] 
[122.59375] 
[122.59375] 
[122.59375] 
[122.59375] 
[122.59375] 
[122.59375] 
[122.59375] 
[122.59375] 
[122.59375] 
[122.59375] 
[122.59375] 
[122.59765625] 
[122.59765625] 
[122.59765625] 

Так на самом деле, что пошло на то, что процесс Python держит на пуле памяти учитывая то, что он использует, чтобы избежать необходимости держать запроса больше памяти (и затем освобождая его) от ОС хоста. Я не знаю всех технических деталей позади этого, но это, по крайней мере, то, что происходит.

Смежные вопросы