python内存浅析
python内存浅析
栈内存区【stack】:用于直接分配数据,存取数度较快,数据存储不稳定,适用于小数据块的快速存取,一般在程序中用于存储变量数据。
方法区【data】:主要用于加载程序中的代码数据、二进制数据、方法数据等等程序运行需要的预加载数据
静态区【static】:主要用于加载存储程序中的一些静态数据、常量数据等等,在PYTHON中的不可变数据类型的数据也会存储在静态常量区内存中
堆内存【heap】:存储数据稳定持久,一般用于存储加载较为重量级的数据,如程序运行过程中的对象都是存在堆内存中的

一、不可变类型数据
一般的基本数据类型都是不可变类型
python中的一切都是对象,可以通过id()函数查询对象在内存中的地址数据,不可变数据类型是在定义了数据之后,修改变量的数据,变量不会修改原来内存地址的数据而是会指向新地址,原有的数据保留,这样更加方便程序中基本数据的利用率。

用python赋值皆标签的理念理解一下:
a=3:常量区中创建地址为8791523976080的值=3,用a标签贴在他身上。
b=a: b标签和a标签一样 贴在地址为8791523976080的值上
a=4:栈中创建地址为8791523976112的值=4,把a标签从”地址8791523976080”上取下贴在“地址8791523976112”上
此时b还是贴在”地址8791523976080”上
同理分析num[4]
发现原来 “4”这个常亮就是存在“地址8791523976112”中,
所以num[3]应该还是贴”地址8791523976080”
果然:


再看一个加深理解:

在函数 chg_nums()中,n标签贴向了 “4”但他是函数的内部变量,也没有return出去,所以函数调用完,n标签被回收了,没有影响a标签
对于不可变类型,
在同一个代码块中进行多次使用时会将该类型的对象,直接创建在常量区,在任意引用时候的时候直接赋值内存地址因为不可变类型的对象数据不会发生变化,所以内存中存储一份即可!优化程序执行效率一般情况下,可变类型的对象会创建在堆内存中;不可变类型的对象会创建在常量区内存中
整数类型:-5~256:在解释器加载时,已经自动分配了这些数字的内存
超出-5~256范围的整数,在一个代码块中申请一次内存
(注:交互模式:一行命令就是一个代码块,IDE模式~工具开发:一个模块就是一个代码块)
二、可变类型数据
一般的组合数据类型或者自定义数据类型都是可变数据类型,可变类型是在定义过数据类型之后,修改变量的数据,内存地址不会发生变化。


所以就出现了浅拷贝和深拷贝这一说:
上图 list_b=list_a就是赋值。
浅拷贝: copy.copy(影子拷贝)
深拷贝:copy.deepcopy
如果浅拷贝或深拷贝,则应该在堆内存中新建一片区域用于存储一个一模一样的列表


至于浅拷贝、深拷贝的差别,很值得一说。
简单来说:如果对象的子对象中还有可变数据类型(如:a=[1,2,3,[4,5]]),浅拷贝会直接引用地址(原[4,5]的地址直接引用过来),而深拷贝则会开辟新的内存空间对其存储。
举个简单的例子:
import copy
a=[1,2,3,4,["a","b"]]
b=a
c=copy.copy(a)
print(c is a)
print(id(c))
print(id(a))
print(id(a[4]))
print(id(c[4]))
d=copy.deepcopy(a)
print(id(d[4]))
a.append(5)
a[4].append("c")
print(a)
print(b)
print(c)
print(d)运行结果如下:

copy对于一个复杂对象的子对象并不会完全复制,什么是复杂对象的子对象呢?就比如序列里的嵌套序列,字典里的嵌套序列等都是复杂对象的子对象。对于子对象,python会把它当作一个公共镜像存储起来,所有对他的复制都被当成一个引用,所以说当其中一个引用将镜像改变了之后另一个引用使用镜像的时候镜像已经被改变了。
而deepcopy则是完全复制,和原对象没有一丁点联系了。