Python内存分配
python(或者说动态语言)的内存分配它的原理依然遵循静态语言(如c、java等)。在静态语言中,创建列表需要先声明大小,如需扩充则需要重新声明一个更大的列表,并把原有的列表销毁。我猜测python等动态语言其源码也是相似的实现。不一样的是在静态语言中重新创建列表,必然会导致两个对象的id不一样,而在python中,列表扩充不会影响id变化。
1.空对象不为空
空对象也占用一定内存。我们可以抽象地理解:它们的一部分内存用于创建容器的骨架、记录容器的信息(如引用计数、使用量信息等等)、还有一部分内存则是预分配的。
import sys
sys.getsizeof("") # 49
sys.getsizeof([]) # 64
sys.getsizeof(()) # 48
sys.getsizeof(set()) # 224
sys.getsizeof(dict()) # 240
# 作为参照:
sys.getsizeof(1) # 28
sys.getsizeof(True) # 28
占用内存排序:基础数字<空元组 < 空字符串 < 空列表 < 空集合 < 空字典
2.关于内存扩充
python(或动态语言)内存扩充会一次性分配多个内存,每次新增元素,就使用已有内存,因而避免了再去申请新的内存(超额分配机制)。并且每次扩充时分配的内存会逐渐增大非均匀分配机制。
值得注意:不同元素数量的列表,所占的内存有可能相同
3.静态初始和动态初始化对象
# 动态分配
a=[] # 64
a.append(1) # 96
# 静态分配
a = [1] # 72
同样的内容前面占内存96,而后面静态分配占内存72位。原因是动态分配一次性分配了多(4)个位置,而静态分配就只分配元素数量(1)个内存。
值得注意:在元素个数相等时,静态创建的列表所占的内存有 <= 动态扩容时的内存!
4、消减元素并不会释放内存!
import sys
a = [1, 2, 3, 4]
sys.getsizeof(a) # 初始值:96
a.append(5) # 扩充后:[1, 2, 3, 4, 5]
sys.getsizeof(a) # 扩充后:128
a.pop() # 缩减后:[1, 2, 3, 4]
sys.getsizeof(a) # 缩减后:128
这里就跟静态语言实现列表扩充十分相似,列表进行扩充后删减不会去特意的缩减内存(我们有理由相信该列表还会添加)。
5、空字典不等于空字典!
import sys
sys.getsizeof([]) # 64
sys.getsizeof(set()) # 224
sys.getsizeof(dict()) # 240
a = [1, 2, 3]
b = {1, 2, 3}
c = {'a':1, 'b':2, 'c':3}
sys.getsizeof(a) # 88
sys.getsizeof(b) # 224
sys.getsizeof(c) # 240
a.clear() # 清空后:[]
b.clear() # 清空后:set()
c.clear() # 清空后:{},也即 dict()
# 承接前面的清空操作:
sys.getsizeof(a) # 64
sys.getsizeof(b) # 224
sys.getsizeof(c) # 72
调用clear()方法可以实现真正意义上的清空。其他类型均没问题,而字典在调用该方法后内存仅占72,这比空字典还要小很多很多!为什么会这样呢?待研究……

浙公网安备 33010602011771号