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,这比空字典还要小很多很多!为什么会这样呢?待研究……

posted @ 2019-09-29 10:06  小夏02  阅读(366)  评论(0)    收藏  举报