实际问题:
在游戏中,定义了玩家类player,每有一个在线玩家,在服务器内则有一个player的实例,当在线人数很多时,将产生大量实例(百万级)
如何降低这些大量实例的内存开销?
解决方案:
定义类的__slots__属性,声明实例有哪些属性(关闭动态绑定)
创建两个类,区别为Player2有slots方法
import sys
import tracemalloc
class Player1(object):
def __init__(self, uname, uid, level=1):
self.uname = uname
self.uid = uid
self.level = level
class Player2(object):
__slots__=('uname', 'uid', 'level')
def __init__(self, uname, uid, level=1):
self.uname = uname
self.uid = uid
self.level = level
p1 = Player1('juran1', '001')
p2 = Player2('juran2', '002')
# 查找p1,p2中的属性
print(dir(p1))
print(dir(p2))
print(set(dir(p1)) - set(dir(p2)))
# {'__dict__', '__weakref__'}
wearef 弱引用
dict 动态绑定属性(主要的内存浪费)
p1.x = 'juran11'
print(p1.__dict__)
# {'uname': 'juran1', 'uid': '001', 'level': 1, 'x': 'juran11'}
# 所以可通过字典形式添加
p1.__dict__['y'] = 'juran111'
print(p1.__dict__)
# {'uname': 'juran1', 'uid': '001', 'level': 1, 'y': 'juran111'}
可是对Player2添加了__slot2__ 后对添加属性就会报错
p2.x = 'juran22'
# AttributeError: 'Player2' object has no attribute 'x'
所以slot方法限制了dict动态绑定属性
下面通过对内存的分析来反映Player1 和 Player2
1 首先调用sys库中的getsizeof方法分析(说明一下这种方法只能分析出字符串,列表等确定的内存大小)
print(sys.getsizeof(p1.__dict__))
print(sys.getsizeof(p1.uname))
print(sys.getsizeof(p1.uid))
# 112
# 55
# 52
说明主演占据内存的还是dict动态绑定属性
2 调用tracemalloc库进行分析
tracemalloc.start()
p1 = [Player1(1, 2, 3) for _ in range(100000)] # 16.8 MiB
p2 = [Player2(1, 2, 3) for _ in range(100000)] # 7837 KiB
end = tracemalloc.take_snapshot()
# 直接对文件大小变化进行统计
top = end.statistics('filename')
for stat in top[:10]:
print(stat)
显而易见,没有dict动态绑定属性的占据更少的内存空间