2013-06-05 2 views
5

У меня есть проблема с простым связанным списком Python и его потреблением памяти.Плохое выделение памяти в Python LinkedList

Это код:

import sys 

class Record: 
    def __init__(self,elem): 
     self.elem=elem 
     self.next=None 

    def size(self): 
     print 'elem.size = ', sys.getsizeof(self.elem) 
     print 'next.size = ', sys.getsizeof(self.next) 


class LinkedList: 
    def __init__(self): 
     self.first=None 
     self.last=None 

    def addAsLast(self,elem): 
     rec=Record(elem) 
     if self.first==None: 
      self.first=self.last=rec 
     else: 
      self.last.next=rec 
      self.last=rec 

if __name__=="__main__": 
    l=LinkedList() 
    r = Record(1) 
    r.size() 

    maxx = 10000000 
    r = range(1, maxx) 
    print 'size of r: ', sys.getsizeof(r) 
    print 'size of r[n-1]: ', sys.getsizeof(r[maxx-2]) 

    for i in r: 
     if(i% (maxx/10) == 0): print '.' 
     l.addAsLast(i) 
    print "The End" 

Моя проблема заключается в следующем: работает этот скрипт потребляет 1,7 Гб оперативной памяти моей.

Выход:

elem.size = 12 
next.size = 8 
size of r: 40000028 
size of r[n-1]: 12 

так, давайте делать некоторые быстрые математику:

10 миллионов Record.

Каждая запись получил 12 байт (элем) + 8 байт (указатель на следующий) = 20 байт

20 байт * 10 миллионов = 200.000.000 байт = 190,7 MB

Даже если я должен учитывать список, выделенный функцией range() (около 30 МБ), как я могу управлять этим огромным разрывом в потреблении памяти? Я сделал какую-то глупую ошибку в этом коде? Я надеюсь, что ответ заставит меня почувствовать стыд и жаль, что я спросил его, но, чтобы понять, мне просто интересно, что происходит!

Заранее за вашу помощь.

+2

Не то, чтобы он составлял большой пробел, но вы должны изменить '' '' '' '' метод '' 'Record''' и заставить его печатать' '' sys.sizeof (self) '' 'вместо двух компонентных элементов. Это 32 байта, а не 20, потому что в структуре класса есть накладные расходы. –

+1

фрагментация добавит что-то, я думаю. Я бы попробовал что-то вроде 'recpool = [None] * 10000000; ... rec = recpool [j]; j + = 1' и посмотреть, что произойдет. – Elazar

+1

, попробуйте 'gc.disable()'. – Elazar

ответ

0
>>> class Record: 
...  def __init__(self, elem): 
...    self.elem = elem 
...    self.next = None 
... 
>>> r = Record(1) 
>>> sys.getsizeof(r) 
72 

Или я что-то упускаю?

Кроме того, в моей системе:

>>> sys.getsizeof(1) 
24 
>>> sys.getsizeof(None) 
16 
+0

это 56 на моей машине – Elazar

+0

Думаю об этом сейчас : 56 или 72 байта, он все равно не должен содержать до 1,7 ГБ. В 56 байт эта математика имеет значение ~ 600 МБ. Я буду думать об этом :) – 2rs2ts

+0

56 + 28 = 84. округление - 88. 88 * 10000000 ~ = 0,88 ГБ. добавьте фрагментацию и GC накладные расходы, и у вас есть что-то близкое. – Elazar

0

Измененные печати следующим образом:

class Record: 
    def __init__(self,elem): 
     self.elem=elem 
     self.next=None 

    def size(self): 
     print 'Record size = ', sys.getsizeof(self) 
     print 'elem.size = ', sys.getsizeof(self.elem) 
     print 'next.size = ', sys.getsizeof(self.next) 

Выход:

Record size = 72 
elem.size = 24 
next.size = 16 

Таким образом, каждый из моих связного списка узлов 72 байт x 10M должно быть 720MB, .72GB

Я запустил программу и, используя верхнюю часть, увидел, что накладные расходы памяти составляют 3,6 ГБ. Мой размер elem двойной, и я замечу вдвое больше, чем потребляемая вами память (3.6G, по сравнению с 1.7G).

Это должно быть связано с дополнительными издержками памяти python, такими как сбор мусора.

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