快捷搜索:  汽车  科技

python内存释放机制(一文读懂Python内存存储机制)

python内存释放机制(一文读懂Python内存存储机制)• 人工智能开发环境搭建系列• 快速入门Python数据科学系列• 面向人群:零基础编程爱好者• 专栏计划:接下来会逐步发布跨入人工智能的系列博文,敬请期待• Python零基础快速入门系列

这是机器未来的第8篇文章

写在前面:

• 博客简介:专注AIoT领域,追逐未来时代的脉搏,记录路途中的技术成长!

• 专栏简介:本专栏的核心就是:快!快!快!2周快速拿下Python,具备项目开发能力,为机器学习和深度学习做准备。

• 面向人群:零基础编程爱好者

• 专栏计划:接下来会逐步发布跨入人工智能的系列博文,敬请期待

• Python零基础快速入门系列

• 快速入门Python数据科学系列

• 人工智能开发环境搭建系列

• 机器学习系列

• 物体检测快速入门系列

• 自动驾驶物体检测系列

• ......

@toc

python内存释放机制(一文读懂Python内存存储机制)(1)

1. 变量的存储机制

Python中的一切都是对象,变量是对象的引用!对象存于堆中,变量存于栈中。

1.1 什么是堆、栈?

堆栈都存在于内存中,在运行时分配的内存空间。对象存于堆中,变量存于栈中, 堆区存变量值 栈区存变量名。栈区存放变量名和其变量值的内存地址 通过这个内存地址 变量名可以找到变量值。

1.2 直接引用和间接引用1.2.1 直接引用:变量名直接关联变量值

直接引用常见于整数类型和字符串类型,修改它们的值,其实已经指向了其它的对象。直接引用的数据类型也被称为不可变数据类型 *不可变数据类型在内存中存储的值仅存储一份 后续定义的变量如果值相等都指向用一个对象 即 x1 is x2 and x1 == x2为True*.

变量名(变量值的地址)存于内存栈区,变量值存于堆区 变量名直接关联变量值。

x=10 y=20 print(hex(id(x)) hex(id(y)))

0x7ff97c90f020 0x7ff97c90f160 # 从输出中可知,x,y指向两个不一样的对象

python内存释放机制(一文读懂Python内存存储机制)(2)

当执行x = y 时,你会发现x已经指向了一个新的对象,和原来的对象链路已经断开了。

x=10 y=20 print(hex(id(x)) hex(id(y))) x=y print(hex(id(x)) hex(id(y)))

0x7ff97c90f020 0x7ff97c90f160 0x7ff97c90f160 0x7ff97c90f160 # 从输出中可知,x y已经指向了同一个对象

python内存释放机制(一文读懂Python内存存储机制)(3)

注意:字符串的内容是不可以更改的,修改会直接报错!!!

name="David" name[2]='a'

TypeError Traceback (most recent call last) C:\Users\ZHOUSH~1\AppData\Local\Temp/ipykernel_9084/4053774855.py in <module> 1 name = "David"

2 name[2] = 'a'

TypeError: 'str' object does not support item assignment

1.2.2 间接引用:变量名通过列表对象间接访问变量值

间接引用出现在容器类型里,如列表、元组、字典等。

定义列表变量l,其存储结构如图:变量l存储于栈区,变量l通过存储在堆区中列表对象内存地址访问列表对象,然后列表对象再通过其列表中存储的元素地址访问具体的变量值'a' 和 'b'。

l=['a' 'b']

python内存释放机制(一文读懂Python内存存储机制)(4)

如果修改变量l[1]的值,例如l[1] = 'c',则列表的存储地址不会发生变化,但是列表对象第0个元素的地址会发生变化,其为字符'c'的内存地址,并指向字符对象'c' 但是整个过程变量l的地址不会发生变化.

python内存释放机制(一文读懂Python内存存储机制)(5)

特别注意:间接引用变量既是值相等 这两个变量也不一定是同一个变量;而对于不可变数据类型 只要值相等 那么这两个变量一定是同一个变量.

x1=[1 2 3 4 5 3 6 7] x2=[1 2 3 4 5 3 6 7] x1isx2 print(hex(id(x1)) hex(id(x2)))

0x2913b25ab08 0x2913cdf35c8

2. 浅拷贝与深拷贝
  • • 直接赋值:其实就是对象的引用(别名)。
  • • 浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象。
  • • 深拷贝(deepcopy):copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象。
2.1 直接赋值

其实就是对象的引用(别名)

l1=[1 'abc' [2 3]] l2=l1 print(id(l1) id(l2))

2822815412936 2822815412936

l2直接指向l1引用的对象 l1和l2的内存地址是一样的 存储结构如图.

python内存释放机制(一文读懂Python内存存储机制)(6)

2.2 浅拷贝

拷贝父对象,不会拷贝对象的内部的子对象。

importcopy l1=[1 'abc' [2 3]] l2=copy.copy(l1) print(id(l1) id(l2)) print('l1:' id(l1[0]) id(l1[1]) id(l1[2])) print('l2:' id(l2[0]) id(l2[1]) id(l2[2]))

2822786373512 2822786371656 # l1和l2的内存地址不一样 是两个不一样的变量 l1: 140709513457408 2822710032120 2822785142088 l2: 140709513457408 2822710032120 2822785142088 # l1和l2的元素的内存地址是一样的 包括元素中的列表变量(是直接指向过去的) 验证了仅拷贝父对象的描述.

python内存释放机制(一文读懂Python内存存储机制)(7)

2.3 深拷贝

copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象。

importcopy l1=[1 'abc' [2 3]] l2=copy.deepcopy(l1) print(id(l1) id(l2)) print('l1:' id(l1[0]) id(l1[1]) id(l1[2]) id(l1[2][0]) id(l1[2][1])) print('l2:' id(l2[0]) id(l2[1]) id(l2[2]) id(l2[2][0]) id(l2[2][1]))

2822786372360 2822815414472 # l1和l2的内存地址不一样 是不同的变量 l1: 140709513457408 2822710032120 2822786363528 140709513457440 140709513457472 l2: 140709513457408 2822710032120 2822786366024 140709513457440 140709513457472

l2对l1进行了深拷贝 直至数据类型为不可变类型为止.

从输出中可以看到:

  • • l1和l2的内存地址不一样了 是不同的变量;
  • • l1和l2的前2个成员变量的内存是一样的 因为它们直接引用的不可变数据类型;
  • • 第3个成员变量为一个列表 深拷贝时创建了一个新的列表变量 从输出可知l1[2]的内存地址为2822786363528 l2[2]的内存地址为2822786366024.
  • • 但l1[2]和l[3]列表中的元素的内存地址又变为一样的了 因为它们都是不可变数据类型 指向同一个对象(注:不可变数据类型仅在内存中存储一份).

python内存释放机制(一文读懂Python内存存储机制)(8)

《Python零基础快速入门系列》快速导航:

  • • Python快速入门系列(1) 人工智能序章:开发环境搭建Anaconda VsCode JupyterNotebook(零基础启动)
  • • Python快速入门系列(2)一文快速掌握Python基础语法
  • • Python快速入门系列(3)AI数据容器底层核心之Python列表

推荐阅读:

  • • 物体检测快速入门系列(1)-Windows部署GPU深度学习开发环境
  • • 物体检测快速入门系列(2)-Windows部署Docker GPU深度学习开发环境
  • • 物体检测快速入门系列(3)-Tensorflow 2.x Object Detection API快速安装手册
  • • 物体检测快速入门系列(4)-基于Tensorflow2.x Object Detection API构建自定义物体检测器

python内存释放机制(一文读懂Python内存存储机制)(9)

猜您喜欢: