2013-08-12 18 views
4

我瞎搞與sys.getsizeof和有點驚訝,當我到列表和數組:什麼導致python列表的(大)大小?

>>> from sys import getsizeof as sizeof 
>>> list_ = range(10**6) 
>>> sizeof(list_) 
8000072 

相比數組:

>>> from array import array 
>>> array_ = array('i', range(10**6)) 
>>> sizeof(array_) 
56 

原來整數列表趨向的大小它的所有元素的大小的1/3,所以它不能阻礙他們:

>>> sizeof(10**8) 
24 
>>> for i in xrange(0,9): 
... round(sizeof(range(10**i))/((10**i) * 24.0), 4), "10**%s elements" % (i) 
... 
(3.3333, '10**0 elements') 
(0.6333, '10**1 elements') 
(0.3633, '10**2 elements') 
(0.3363, '10**3 elements') 
(0.3336, '10**4 elements') 
(0.3334, '10**5 elements') 
(0.3333, '10**6 elements') 
(0.3333, '10**7 elements') 
(0.3333, '10**8 elements') 

是什麼原因導致這種行爲,既list很大,但沒有它的所有元素那麼大,array是如此之小?

+2

首先,列表的sys.getsizeof()不*測量被引用對象佔用多少內存。它只是**列表對象本身。 –

+0

這是Python 2還是3?對我來說,數組的內存大小是'4000056L'。 –

+0

linux2上的Python 2.7.3 [GCC 4.7.2](在Debian上運行,Linux 3.2.0-4-amd64) – Alex

回答

3

您所遇到的問題有沒有反映array對象他們的大小正確。

直到Python 2.7.3對象的.__sizeof__()方法確實不是準確地反映了大小。在Python 2.7.4及更新版本以及2012年8月之後發佈的任何其他新Python 3版本中,增加了大小的bug fix was included

有關python 2.7.5我看到:每符號整數

>>> sys.getsizeof(array_) 
4000056L 

,其與56個字節大小的符合我的64位系統需要的基礎對象,加上4個字節含有。

關於Python 2.7.3,我看到:在我的系統中使用的每基準8個字節

>>> sys.getsizeof(array_) 
56L 

的Python list對象,所以它們的大小自然是幾乎大了一倍。

+0

完美。爲什麼列表中的4個額外字節?類型信息? – Alex

+0

對象引用計數和堆鏈表指針,實際上。 –

+0

@MartijnPieters真的嗎?我認爲這與64位系統上的指針大小有關。 – omz

0

getsizeof函數不會像列表一樣測量容器中項目的大小。你需要添加所有的單個元素。

Here是一個配方來做到這一點。

這裏轉載:

from __future__ import print_function 
from sys import getsizeof, stderr 
from itertools import chain 
from collections import deque 
try: 
    from reprlib import repr 
except ImportError: 
    pass 

def total_size(o, handlers={}, verbose=False): 
    """ Returns the approximate memory footprint an object and all of its contents. 

    Automatically finds the contents of the following builtin containers and 
    their subclasses: tuple, list, deque, dict, set and frozenset. 
    To search other containers, add handlers to iterate over their contents: 

     handlers = {SomeContainerClass: iter, 
        OtherContainerClass: OtherContainerClass.get_elements} 

    """ 
    dict_handler = lambda d: chain.from_iterable(d.items()) 
    all_handlers = {tuple: iter, 
        list: iter, 
        deque: iter, 
        dict: dict_handler, 
        set: iter, 
        frozenset: iter, 
        } 
    all_handlers.update(handlers)  # user handlers take precedence 
    seen = set()      # track which object id's have already been seen 
    default_size = getsizeof(0)  # estimate sizeof object without __sizeof__ 

    def sizeof(o): 
     if id(o) in seen:  # do not double count the same object 
      return 0 
     seen.add(id(o)) 
     s = getsizeof(o, default_size) 

     if verbose: 
      print(s, type(o), repr(o), file=stderr) 

     for typ, handler in all_handlers.items(): 
      if isinstance(o, typ): 
       s += sum(map(sizeof, handler(o))) 
       break 
     return s 

    return sizeof(o) 

如果您使用的配方和名單上運行此,你可以看到其中的差別:

>>> alist=[[2**99]*10, 'a string', {'one':1}] 
>>> print('getsizeof: {}, total_size: {}'.format(getsizeof(alist), total_size(alist))) 
getsizeof: 96, total_size: 721 
+3

但這並不能解釋'array'情況。 – glglgl

+0

「數組」不是**容器。在Mac上,我可以準確地反映出Linux的大小,而在Linux上卻沒有。 –