Python 中的内存分配关系(变量,列表,元祖等)

一、Python 的内存管理模式

Python采用基于值的内存管理模式,相同的值在内存中只有一份

首先明确一点,整数、实数、字符串是真正意义上的值,而上面那句话中的“值”主要指整数和短字符串

对于列表、元组、字典、集合以及range对象、map对象等容器类对象,它们不是普通的“值”,即使看起来是一样的,在内存中也不会只保存一份。
在这里插入图片描述
其实对于任意对象,系统会维护一个计数器时刻记录该对象被引用的次数

每次有新的对象引用该对象,其计数器加1,每次使用del释放一个引用,其计数器减1,如果垃圾回收机制发现某对象的引用次数为0,则将其删除。

对于 [-5,256] 之间的整数,系统会进行缓存,因为系统本身也有大量对象在引用这些值

在这里插入图片描述

在这里插入图片描述

把整数或者字符串放在列表或者元祖中,也只会保存一份

在这里插入图片描述

二、元组和列表的内存分配机制

List:动态数组,元素可变,可改变大小(append,pop 等)
Tuple:静态数组,不可变,数据一旦创建后不可改变

(1) List 的内存利用
当创建N个元素的List时,Python的动态内存分配长N+1个元素的内存,第一个元素存储列表长度,和列表的元信息

当Append一个元素时,Python将创建一个足够大的列表,来容纳N个元素和将要被追加的元素。重新创建的列表长度大于N+1(虽然我们只触发一次append操作),实际上,为了未来的Append操作,M个元素长度(M>N+1)的内存将会被额外分配,然后,旧列表中的数据被copy到新列表中,旧列表销毁。

额外内存的分配,只会发生在第一次Append操作时,当我们创建普通列表时,不会额外分配内存

这里的哲学是,一个Append操作很可能是很多Append操作的开始,通过额外分配内存来减少可能的内存分配和内存copy的次数。

补充

python 采用的是分离式结构动态数组的方法
在这里插入图片描述

用户持续添加列表元素时,动态数组预留的空间迟早会被耗尽,列表类会向系统请求一个新的,更大的内存空间,并初始化该数组,旧的数组将会被系统收回
因为存储的只是引用地址,地址重新指向了新分配的数组,所以 列表的 id 不会发生变化
可以自己写个循环,不断append,尝试下

import sys
list,num =[],0
while num <= 100 :
    length = len(list)
    size = sys.getsizeof(list)
    print('length = '+str(length)+'  size = '+str(size) + ' -- ' + str(id(list)))
    list.append(None)
    num += 1

(2)Tuple 的内存利用
虽然Tuple不支持 改变,但是我们可以粘贴两个元祖组成一个新的元组,这个操作类似于List 的 append,但是又不会额外的分配内存。但我们不能把它当成append,因为每次都会进行一个分配内存和内存copy操作。

三、copy 和分片

在Python中,copy和分片才会新建的列表地址,引用的是列表的引用地址,列表里存的是各个元素的地址

(1)对列表的引用,列表的内存地址不变
在这里插入图片描述
同样,对一个列表的修改操作,也会影响到另一个被引用的列表
在这里插入图片描述
(2) copy 和分片可以达到新建独立列表的目的,原先列表的改变不会对其产生影响
在这里插入图片描述
(3)无论是引用,或者copy,分片,只要具体的值不变,那么内存中该值的地址就不会变
在这里插入图片描述


【参考文章】

【1】https://blog.csdn.net/oh5w6hinug43jvrhhb/article/details/79308072
【2】https://www.jianshu.com/p/24090fb63968
【3】https://www.cnblogs.com/xfxing/p/8687111.html


版权声明:本文为nanhuaibeian原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。