python 的内存回收,及深浅Copy详解
数字(num)、字符串(str)、元组(tuple)、布尔值(bool)
接下来我们讲完后你就懂了为什么它们是不可变对象了。
都知道python中一切都是对象,而变量就是这些对象的引用,什么意思呢
综合表述:
变量是一个系统表的元素,拥有指向对象的连接的空间
对象是被分配的一块内存,存储其所代表的值
引用是自动形成的从变量到对象的指针
特别注意: 类型属于对象,不是变量
>>> c = 17 #1 数字17就是一个对象,实实在在存在计算机内存中
>>> d = c #2 c 和 d 都是对象17的一个引用,c指向17,d也是
>>> id(c) #3
1462698960
>>> id(d) #4
1462698960
在#1 处我们定义了各一个变量c,c指向了17(把17赋值给c),对象17的一个引用c
然后在#2处,又定义了一个变量d ,把c赋值给了d,接着#3、#4查看了c、d的 id 相同,
发现是同一个对象(17),对象17的引用+1
引用:
对象17的引用现在有两个了
变量:
在内部,变量事实上是到对象内存空间的一个指针
1.2.1 python本身是一门动态语言
与c/c++ /java不同,不需要事先定义变量开辟内存空间,然后给变量赋值,存储到变量的内存空间中。使用结束,当然也不需要你去手动调用析构函数释放内存了。
python会预先申请一部分内存空间,在运行时定义了变量-对象,根据对象确认它的type,将对象放到申请的内存中,python每过一段时间就来检查一次,当有对象的引用为0时,就回收这块内存,返还回先申请的内存空间,而不是计算机。这样避免了内存碎片过多问题。
1.2.2 怎么减少对象的引用
- 将变量引用指向其他对象
>>> c = 17
>>> d = c
>>> id(c) #1
1462698960
>>> id(d) #2
1462698960
>>> c = "yue" #3
>>> id(c) #4
612496081896
>>> d #5
17
可以看到#1、#2处c、d都还是对象17的引用,当#3处把变量c 指向新对象字符串"yue" 时,#4处发现变量c指向的对象id变了,的确不是17了,所以对象17的引用 -1 如下图
注意:这儿改变了c的引用,可是#5处d却没有跟着c变,还是对象17
同理当你再把d指向其他对象时,对象17的引用就减为零,当Python来检查时,就会回收这块内存了
2.删除变量(引用)
>>> del d
>>> d
Traceback (most recent call last):
File "<stdin>", line 1, in <modul
NameError: name 'd' is not defined
不啰嗦,这样对象17就彻底被删除了,上图时对象17只剩下一个变量引用d。
同理对于函数,定义函数时,函数名就是一个引用,当其他地方调用函数时,引用+1,调用结束 -1 。在函数的命名空间中可以查到这些,详情看我这篇文章
python的内存回收就到这儿:总结:回收机制为判断对象 引用是否为0,如果为零就回收内存到自己申请的内存空间,不是计算机硬盘。
通过上面的式子和图理解我们也知道了,当定义变量为数字、字符串、tuple、布尔值时,这些变量所对应的对象在内存空间的值是不可改变了,你重新赋值,也只是把变量引用指向了另一个对象,id变了,本身那个对象是不可变的。
>>> a = (1, 'one')
>>> id(a)
612494666568 #1
>>> a[0] = 2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> a[0]
1
>>> a = (2, 'two')
>>> id(a)
612494666824 #2
#---------------------------------------------
>>> a = 'findxgo' #3
>>> id(a)
612496082848
>>> a.replace('x','--X--') #4
'find--X--go'
>>> id(a) #5
612496082848
>>> a = a.replace('x', '-X-') #6
>>> id(a)
612496086704
在#3出定义了字符串a,#4处替换x,得到一新字符串,但是原字符串还是#5id没变,当#6把替换的字符串赋值给变量a,a的引用指向了替换后新字符串
如图:指两个或多个变量指向同一个内存空间
![](https://images2018.cnblogs.com/blog/1226829/201808/1226829-20180804124229776-277665676.png)
如果删掉c后, 不会影响d
拷贝概念的引入就是针对:可变对象的共享引用潜在的副作用而提出的。
2.2.1 指python中,存储在内存可以被修改的对象:列表、字典等
上面说的数字、字符串、元组等不可变类型,在你复制时也就是增加了一个引用,无法去改变内存的值。对对象的其中一个引用变量操作不会影响其他引用。
但是对于列表、字典:
>>> list_1 = [5, 2, 1]
>>> L2 = list_1 #1 将list_1赋值给L2
>>> list_1,L2
([5, 2, 1], [5, 2, 1])
>>> list_1[2] = '01314' #2 修改list_1 索引2处的值
>>> list_1,L2
([5, 2, '01314'], [5, 2, '01314'])
可以看到#1 上面定义一个列表,赋值给L2后,L2、list_1对应完全一样的值(列表)事实上,他两的确对应着一块内存,你可以自己去查id,是那块内存(列表)的两个引用
当你去在list_1,或者L2进行操作时,改变了对应内存的值,所以#2下面两个值都变了。python中同一块内存(对象)的不同引用改变对象所以引用都会被影响。
同理字典:通过自己哈希表将key计算后得到的内存地址就是存放value的地方,当你用如上同样的方式改变哪儿的值,所有引用都会被影响。
上述的情况如果想避免,有两种方式,原理都一样:copy一份放到另一个内存,变成同样(value)的两个对象,当你修改其中一个时,另一个不会影响。
1、切片复制:完全切片
>>> list_1 = [5, 2, 1]
>>> L2 = list_1[:] #1 此处完全切片,复制
>>> list_1,L2
([5, 2, 1], [5, 2, 1])
>>> id(list_1) #2 查看id
612496051784
>>> id(L2) #3
612496051720
如上:#1处完全切片也可以L2 = list_1[0: -1]
是一样的,#2,#3处可以看见,id不同,就不是同一个对象,只是里面的value相同而已
同理copy模块的copy方法,这是浅拷贝。
1. 深浅拷贝,即可用于序列,也可用于字典
>>> import copy
>>> dict_1 = {'copy': '浅拷贝', 'deepcopy': ['deep', '第二层', ' 深拷贝']}
>>> D2 = copy.copy(dict_1) #浅拷贝:只拷贝顶级的对象,也说:父级对象
>>> D3 = copy.deepcopy(dict_1) #深拷贝:拷贝所有对象,顶级对象及其嵌套对象。或者说:父级对象及其子对象
>>> print("源:{0: ^18}\n浅拷贝:{1}\n深拷贝:{2}".format(id(dict_1),id(D2),id(D3)))
源: 37811303432
浅拷贝:37813197256
深拷贝:37813160264
2.改变源顶级对象,深浅拷贝不会变
>>> dict_1['copy'] = 'n_copy'
>>> dict_1;D2;D3
{'copy': 'n_copy', 'deepcopy': ['deep', '第二层', ' 深拷贝']}
{'copy': '浅拷贝', 'deepcopy': ['deep', '第二层', ' 深拷贝']}
{'copy': '浅拷贝', 'deepcopy': ['deep', '第二层', ' 深拷贝']}
3.改变源嵌套对象,浅拷贝变了,深拷贝不变
>>> dict_1['deepcopy'][1] = '嵌套层'
>>> dict_1;D2;D3
{'copy': 'n_copy', 'deepcopy': ['deep', '嵌套层', ' 深拷贝']}
{'copy': '浅拷贝', 'deepcopy': ['deep', '嵌套层', ' 深拷贝']}
{'copy': '浅拷贝', 'deepcopy': ['deep', '第二层', ' 深拷贝']}
这儿的浅拷贝,只拷贝了父级对象,在'deepcopy'对应的哪儿就是只拷贝了内存地址,而深拷贝还要去内存地址拷贝内容回来赋值
原理看到这儿,差不多也懂了,就不罗嗦了!
- 深浅拷贝都是对源对象的复制,占用不同的内存空间
- 如果源对象只有一级目录的话,源做任何改动,不影响深浅拷贝对象
- 如果源对象不止一级目录的话,源做任何改动,都要影响浅拷贝,但不影响深拷贝
- 序列对象的切片其实是浅拷贝,即只拷贝顶级的对象
一个有意思的练习题
import copy
a = [1,2,3,[4,5],6]
b=a
c=copy.copy(a)
d=copy.deepcopy(a)
b.append(10)
c[3].append(11)
d[3].append(12)
a,b,c,d分别为什么?
答案我放评论
python 的内存回收,及深浅Copy详解的更多相关文章
- Python的深浅copy详解
Python的深浅copy详解 目录 Python的深浅copy详解 一.浅copy的原理 1.1 浅copy的定义 1.2 浅copy的方法 二.深copy的原理 2.1 深copy的定义 2.2 ...
- 深浅copy详解
一. 前言 在python中,对象的赋值和深浅copy,是有差异的.最终得的值也不同,下面我们就通过几个例子,来看下它们之间的区别. 二. 赋值 list2 = ["jack",2 ...
- JVM垃圾回收算法及回收器详解
引言 本文主要讲述JVM中几种常见的垃圾回收算法和相关的垃圾回收器,以及常见的和GC相关的性能调优参数. GC Roots 我们先来了解一下在Java中是如何判断一个对象的生死的,有些语言比如Pyth ...
- 深拷贝与浅拷贝(mutableCopy与Copy)详解 iOS
深拷贝与浅拷贝(mutableCopy与Copy)详解 iOS ios中并不是所有的对象都支持copy,mutableCopy,遵守NSCopying 协议的类可以发送copy消息,遵守NSMutab ...
- 【python】redis基本命令和基本用法详解
[python]redis基本命令和基本用法详解 来自http://www.cnblogs.com/wangtp/p/5636872.html 1.redis连接 redis-py提供两个类Redis ...
- Python中操作mysql的pymysql模块详解
Python中操作mysql的pymysql模块详解 前言 pymsql是Python中操作MySQL的模块,其使用方法和MySQLdb几乎相同.但目前pymysql支持python3.x而后者不支持 ...
- [转载]windows任务管理器中的工作设置内存,内存专用工作集,提交大小详解
windows任务管理器中的工作设置内存,内存专用工作集,提交大小详解 http://shashanzhao.com/archives/832.html 虽然是中文字,但是理解起来还是很困难,什么叫工 ...
- 七牛云存储Python SDK使用教程 - 上传策略详解
文 七牛云存储Python SDK使用教程 - 上传策略详解 七牛云存储 python-sdk 七牛云存储教程 jemygraw 2015年01月04日发布 推荐 1 推荐 收藏 2 收藏,2.7k ...
- Python调用C/C++动态链接库的方法详解
Python调用C/C++动态链接库的方法详解 投稿:shichen2014 这篇文章主要介绍了Python调用C/C++动态链接库的方法,需要的朋友可以参考下 本文以实例讲解了Python调用C/C ...
随机推荐
- c/c++ 链栈
c/c++ 链栈 链栈 下面的代码实现了以下功能 函数 功能描述 push 压入 pop 弹出 show_list 打印 clear 释放所有内存空间 destroy 释放所有内存空间 nodesta ...
- python爬虫之12306网站--车站信息查询
python爬虫查询车站信息 目录: 1.找到要查询的url 2.对信息进行分析 3.对信息进行处理 python爬虫查询全拼相同的车站 目录: 1.找到要查询的url 2.对信息进行分析 3.对信息 ...
- IntelliJ IDEA 创建Spring+SpringMVC+mybatis+maven项目
参考自:https://www.cnblogs.com/hackyo/p/6646051.html 第一步: 创建maven项目 输入项目名和工程id 选择maven 默认就可以了 刚开始时间比较长, ...
- 清除float浮动造成影响的几种解决方案
1. “清除浮动” ??准确的描述应该是“清除浮动造成的影响” 学习浮动推荐的视频教程<CSS深入理解之float浮动> 2.如何清除浮动造成的影响??? 栗子 块级div元素包含一个内 ...
- win21api、win32gui、win32con三个模块操作系统窗口时一些小技巧
下面这段脚本是操作一个浏览器上弹窗,打开文件窗口,由于脚本 执行速度快,当时未添加第2行的延时时,脚本顺利的执行成功,但弹的窗却没有进行操作,建议后续如果脚本执行到打开弹窗时,延时个几秒再去操作所弹窗 ...
- js 性能篇--dom 重绘 重排 节流
浏览器下载完页面中的所有组件----HTML标记,Js,CSS,图片等之后会解析并生成两个内部数据结构: DOM树 -------- 表示页面结构 渲染树 -------- 表示DOM节点如何显 ...
- SQLite中的WAL机制详细介绍-与回滚日志原理
一.什么是WAL? WAL的全称是Write Ahead Logging,它是很多数据库中用于实现原子事务的一种机制,SQLite在3.7.0版本引入了该特性. 二.WAL如何工作? 在引入WAL机制 ...
- day03-课堂笔记-大纲
字典: # 字典循环: dic.keys() | dic.values() | dic.items()for k, v in dic.items(): print(k, v) # ...
- 四、Oracle 序列、常用函数、多表连接
一.序列定义:是oracle数据库专门用来产生连续且自动增长的数字的对象创建语法:create sequence 序列名(sq_表名) nocache(无缓存) create sequence sq_ ...
- PHP 5 全局变量 - 超全局变量
PHP 全局变量 - 超全局变量 PHP 中的许多预定义变量都是“超全局的”,这意味着它们在一个脚本的全部作用域中都可用.在函数或方法中无需执行 global $variable; 就可以访问它们. ...