trancemalloc
标准库trancemalloc,可以统计内存使用情况
filename:统计整个文件内存
lineno:分开统计
import tracemalloc # from 3.4
tracemalloc.start() # 开始跟踪内存分配
d = [dict(zip('xy',(5, 6))) for i in range(1000000)]
t = [tuple(zip('xy',(5, 6))) for i in range(1000000)]
snapshot = tracemalloc.take_snapshot() # 快照,当前内存分配
top_stats = snapshot.statistics('lineno') # 快照对象的统计
for stat in top_stats:
print(stat)
从上例中可以看出,d的内存消耗为237M,t的内存消耗为191M
所以可以得知内存使用上字典还是较为占用空间的
__slots__
字典为了提升查询效率,必须用空间换时间
一般来说一个实例,属性多一点,都存储在字典中便于查询,问题不大
但是如果数百万个实例,那么字典占的总空间就有点大
Python提供了__slots__
可以把属性字典__dict__
省略
class A:
x = 1
__slots__ = ('y', 'z') # 元组
# __slots__ = ['y', 'z'] # 等同上面
# __slots__ = 'y', 'z' # 等同上面
# __slots__ = 'y'
def __init__(self):
self.y = 5
self.z = 6
def show(self):
print(self.x, self.y)
a = A()
a.show() # 1 5
print(A.__dict__)
# print(a.__dict__) # AttributeError: 'A' object has no attribute '__dict__'
print(a.__slots__) # ('y', 'z')
__slots__
告诉解释器,实例的属性都叫什么,一般来说,既然要节约内存,最好还是使用元组比较好
一旦类提供了__slots__
,就阻止实例产生__dict__
来保存实例的属性
- 动态增加属性
# 为实例动态增加属性
a.newx = 5 # AttributeError: 'A' object has no attribute 'newx'
# 为类动态增加属性
A.newx = 5 # 不报错,因为是类属性
说明实例不可以动态增加属性,而类可以
继承
使用继承,看看__slots__
是否会继承
class A:
x = 1
__slots__ = ('y', 'z') # 元组
def __init__(self):
self.y = 5
self.z = 6
def show(self):
print(self.x, self.y)
class B(A):
pass
print(B().__dict__)
结果表明,__slots__
不影响子类实例,不会继承下去,除非子类里面自己也定义了__slots__
应用场景
使用需要构建在数百万以上众多对象,且内存容量较为紧张,实例的属性简单、固定且不用动态增加的场景
可以使用tracemalloc看看内存使用的差异。
建议使用stats = snapshot.statistics('filename')
查看总内存使用