在执行程序时,如果内存中有大量活动的对象,就可能出现内存问题,尤其是在可用内存总量有限的情况下。在本文中,我们将讨论缩小对象的方法,大幅减少 Python 所需的内存。
为了简便起见,我们以一个表示点的 Python 结构为例,它包括 x、y、z 坐标值,坐标值可以通过名称访问。
Dict
在小型程序中,特别是在脚本中,使用 Python 自带的 dict 来表示结构信息非常简单方便:
>> > ob = { 'x' :1 , 'y' :2 , 'z' :3 }
>> > x = ob[ 'x' ]
>>
'y'
] = y
由于在 Python 3.6 中 dict 的实现采用了一组有序键,因此其结构更为紧凑,更深得人心。但是,让我们看看 dict 在内容中占用的空间大小:
>> > print(sys.getsizeof(ob))
240
如上所示,dict 占用了大量内存,尤其是如果突然虚需要创建大量实例时:
实例数 |
对象大小 |
1 000 000 |
240 Mb |
10 000 000 |
2.40 Gb |
100 000 000 |
24 Gb |
类实例
有些人希望将所有东西都封装到类中,他们更喜欢将结构定义为可以通过属性名访问的类:
class Point :
#
def __init__ ( self , x, y, z) :
self .x = x
self .y = y
self .z = z
>> > ob = Point( 1 , 2 , 3 )
>> > x = ob.x
>>
> ob.y = y
类实例的结构很有趣:
字段 |
大小(比特) |
PyGC_Head |
24 |
PyObject_HEAD |
16 |
__weakref__ |
8 |
__dict__ |
8 |
合计: |
56 |
在上表中,__weakref__ 是该列表的引用,称之为到该对象的弱引用(weak reference);字段 __dict__ 是该类的实例字典的引用,其中包含实例属性的值(注意在 64-bit 引用平台中占用 8 字节)。从 Python 3.3 开始,所有类实例的字典的键都存储在共享空间中。这样就减少了内存中实例的大小:
>>> print ( sys .getsizeof ( ob ), sys .getsizeof ( ob .__dict__ ))
56 112
因此,大量类实例在内存中占用的空间少于常规字典(dict):
实例数 |
大小 |
1 000 000 |
168 Mb |
10 000 000 |
1.68 Gb |
100 000 000 |
16.8 Gb |