這取決於什麼樣的對象,也是其Python實現:-)
在CPython的,這是當他們使用python
,所有的Python對象由一個C結構來表示最什麼人使用, PyObject
。所有'存儲對象'真的存儲PyObject *
。 PyObject
結構保存最基本的信息:對象的類型(指向另一個PyObject
的指針)及其引用計數(一個ssize_t
大小的整數。)C中定義的類型通過將額外信息存儲在對象本身中來擴展此結構,有時會分別分配額外的數據。
例如,元組存儲其長度和PyObject
指針它們所包含的結構本身(內(作爲「延伸」一個的PyObject結構一個PyTupleObject
實現)的結構體包含在該定義中的1長度的數組,但執行分配一個正確大小的內存塊可容納PyTupleObject
結構加上與元組應該容納的項目數量一樣多)。同樣的方式,字符串(PyStringObject
)存儲它們的長度,緩存散列值,一些字符串緩存(「interning」)簿記以及他們數據的實際char *。因此元組和字符串是單塊內存。
另一方面,列表(PyListObject
)存儲它們的長度,其數據爲PyObject **
,另一個爲ssize_t
以跟蹤它們爲數據分配多少空間。因爲Python在各處都存儲PyObject
指針,所以一旦分配了PyObject結構,就不能生長它 - 這樣做可能需要結構體移動,這意味着要查找所有指針並更新它們。由於列表可能需要增長,因此必須從PyObject結構中分別分配數據。元組和字符串不能增長,所以他們不需要這個。 Dicts(PyDictObject
)以相同的方式工作,儘管它們存儲密鑰的密鑰,值和緩存散列值,而不僅僅是項目。字典也有一些額外的開銷,以適應小型字典和專門的查找功能。
但是,這些都是C語言中的所有類型,通過查看C源代碼,您通常可以看到它們將使用多少內存。在Python而不是C中定義的類的實例並不那麼容易。最簡單的情況是經典類的實例並不困難:它是一個PyObject
,它將類PyObject *
存儲到其類中(與存儲在PyObject
結構中的類型不同),PyObject *
到__dict__
屬性(其中保持所有其他實例屬性)和PyObject *
其weakreflist(其由weakref
模塊使用,並且如果必要的話僅初始化。)的實例的__dict__
通常是唯一的實例,因此計算這樣的情況下的「內存大小」時你通常也要計算屬性字典的大小。但它並不一定是特定的實例! __dict__
可以被分配到很好。
新風格的禮儀複雜化。與經典類不同,新樣式類的實例不是單獨的C類型,因此它們不需要單獨存儲對象的類。他們也有餘地__dict__
和weakreflist參考,但不同於經典的情況下,他們不要求任意屬性__dict__
屬性。如果類(及其所有基類)使用__slots__
來定義一組嚴格的屬性,並且這些屬性都不是名稱__dict__
,則該實例不允許任意屬性且不分配字典。另一方面,由__slots__
定義的屬性必須被存儲在的某處。這是通過存儲PyObject
指針直接在的PyObject結構的那些屬性的值來實現,就像是與寫入在C.在__slots__
每個條目從而會佔用PyObject *
,不管類型所做的屬性是否被設置或不。
所有這一切說,這個問題仍然是因爲一切都在Python是保持對象只持有一個參考對象和一切,它有時很難繪製對象之間的界線。兩個對象可以引用相同的數據位。他們可能只有兩個引用該數據。擺脫這兩個對象也擺脫了數據。他們是否都擁有這些數據?只有其中一個,但如果是的話,哪一個?或者你會說他們擁有一半的數據,即使擺脫一個對象不會釋放一半的數據? Weakrefs可以使這個更加複雜:兩個對象可以參考相同的數據,但刪除的對象之一可能會導致其他物體也擺脫其引用到的數據,使數據終究清理。
幸運的是共同情況下是相當容易弄清楚。有Python的內存調試器,可以在跟蹤這些事情時做出合理的工作,如heapy。只要你的類(及其基類)相當簡單,你就可以猜測它將佔用多少內存 - 特別是大量內存。如果您確實想知道數據結構的確切大小,請查閱CPython源代碼;大多數內建類型都是在Include/<type>object.h
中描述並在Objects/<type>object.c
中實現的簡單結構。 PyObject結構本身在Include/object.h
中描述。請記住:它是一路向下的指針;那些也佔據了房間。
這在python實現中肯定會有所不同。你在說哪一個? – 2010-10-31 10:38:54