Python内存分配小秘密,一般人我不告诉他

Python内存分配小秘密,一般人我不告诉他

Python里面如何查看对象所占用的内存?这里我们需要使用到Python内置的sys模块,sys模块负责程序与Python解释器的交互,提供了一系列的函数和变量,用于控制Python的运行时环境。

查看对象占用内存字节大小使用到sys模块的getsizeof()方法。

Python内存分配小秘密,一般人我不告诉他

从上面代码中可以看出:

1.getsizeof方法可计算对象所占用内存字节数

2.getsizeof方法只计算对象直接占用的内存,而不计算对象内所引用对象的内存

看到这里可能有人疑惑,为什么同样的一个列表我这里申请的内存跟上图不一样?

其实这里跟Python解释器有关,32位的解释器创建对象时申请的内存空间要小于64位。

空对象并不“空”

在Python里面有个None表示什么都不是,大家是否好奇过这个None到底是什么?其实None也是一个对象,其类型为NoneType。我们所熟知空对象还有空字符串,空列表,空字典,空元组。当程序创建一个空对象时,这个空对象是否占用内存呢?

Python内存分配小秘密,一般人我不告诉他

虽然都是空对象,但是这些对象在内存分配上并不为“空”。

天啊!空对象居然占用内存,为什么会这样呢?

除了None对象外,其他空对象都是容器,可以理解为创建这个容器本身就需要占用一定的内存,还有一部分内存是对象在初始化的时候预分配。这就是我们看到的空对象也占用这么大内存原因。

空对象并不为空,一部分原因是 Python 解释器为它们预分配了一些初始空间。在不超出初始内存的情况下,每次新增元素,就使用已有内存,因而避免了再去申请新的内存。

内存扩容

创建对象的时候只会分配少量的内存空间,在以后追加元素的对象占用内存必须扩容。那么是如何扩容?每次扩容多大?

下面我们来看下list,set,dict 三个对象的扩容过程

Python内存分配小秘密,一般人我不告诉他

Python内存分配小秘密,一般人我不告诉他

Python内存分配小秘密,一般人我不告诉他

分别给三类可变对象添加 30个元素,看看结果如何:

Python内存分配小秘密,一般人我不告诉他

从结果上我们可以看出来:

1.每次申请内存都是比实际需要内存要多,这种超额申请,主要是为了避免频繁申请内存,导致不必要的开销。

2.每次申请内存不是均匀申请,而是逐渐变大。

删除元素不会释放内存

新增元素的时候会申请新内存,那么删除元素是否新申请的内存是否会释放?

看下面的代码对比:

Python内存分配小秘密,一般人我不告诉他

列表在一扩一缩后,虽然列表的元素回到原样,但是所占用的内存空间可没有自动释放啊。字典,集合等等可变对象同理。

空字典不等于空字典

pop方法是删除一个元素,并不会释放新申请的内存,clear方法是清空所有元素。

下面来看clear方法清空之后内存是否会释放。

先回忆下文章开篇讲的创建空对象讲的每个对象申请的内存,如下图:

Python内存分配小秘密,一般人我不告诉他

调用clear方法后,获得三个空对象,计算每个对象占用的内存。


分享到:


相關文章: