今天是Python的第15篇文章,我们来聊聊Python中内存管理机制,以及循环引用的问题。

Python的内存管理机制

对于工程师而言,内存管理机制异常主要,是绕不外去的一环。若是你是Java工程师,面试的时刻一定会问JVM。C 工程师也一定会问内存泄露,同样我们想要深入学习Python,内存管理机制也是绕不外去的一环。

不外幸亏Python的内存管理机制相对来说比较简朴,我们也不用稀奇深入其中的细节,简朴做个领会即可。

Python内存管理机制的焦点就是引用计数,在Python当中一切都是工具,工具通过引用来使用。

我们看到的是变量名,然则变量名指向了内存当中的一块工具。这种关系在Python当中称为引用,我们通过引用来操作工具。以是凭据这点,引用计数很好明白,也就是说我们会对每一个工具举行统计所有指向它的指针的数目。若是一个工具引用计数为0,那么说明它没有任何引用指向它,也就是说它已经没有在使用了,这个时刻,Python就会将这块内存收回。

简朴来说引用计数原理就是这些,但我们稍微深入一点,来简朴看看哪些场景会引起工具引用的转变。

引用计数的转变显然只有两种,一种是增添,一种是削减,这两种场景都只有4种情形。我们先来看下增添的情形:

首先是初始化,最简朴的就是我们用

赋值操作给一个变量赋值。举个例子:

n = 123

这就是最简朴的初始化操作,虽然123在我们来看是一个常数,然则在Python底层同样被认为是一个常数工具。n是它的一个引用。

第二种情形是引用的通报,最简朴的就是我们将一个变量的值赋值给了另外一个变量。

m = n

好比我们将n赋值给m,它的本质是我们建立了一个新的引用,指向了同样一块内存。若是我们用id操作去查看m和n的id,会发现它们的id是一样的。也就是说它们并不是存储了两份相同的值,而是指向了统一份值。并不是有两个叫做王小二的人,而是王小二有两个差别的账号。

第三种情形是作为元素被存储进了容器当中,好比被存储进了list当中。

a = [1, 2, 123]

虽然我们用到了一个容器,然则容器并不会拷贝一份这些工具,照样只是存储这些工具的引用。

最后一种情形就是作为参数传给函数,在Python当中,所有的传参都是引用通报。这也是为什么,我们经常看到有人会这样写代码的缘故原由:

def test(a):

a.append(3)

a = []

test(a)

print(a)

我们凭据上面枚举的这四种引用计数增添的情形,不难推导出引用削减的情形, 实在基本上是对称的操作。

和初始化对应的操作是

销毁,好比我们建立的工具被del操作给销毁了,那么同样引用计数会-1

del n

和赋值给其他变量名的操作相反的操作是

笼罩,好比之前我们的n=123,也就是n这个变量指向123,现在我们将n赋值成其他值,那么123这个工具的引用计数同样会削减。

n = 124

既然元素存储在容器当中会带来引用计数,那么同样元素

从容器当中移除也会削减引用计数。这个也很好明白,最简朴的就是list挪用remove方式移除一个元素:

a.remove(123)

最后一个对应的就是作用域,也就是当变量

离开了作用域,那么它对应的内存块的引用计数同样会削减。好比我们函数挪用竣事,那么作为参数的这些变量对应的引用计数都市减1。

若是一个工具的引用计数减到0,也就是没有引用再指向它的时刻,那么当Python举行gc的时刻,这块内存就会被释放,也就是这个工具会被消灭,腾出空间来。

注重一下,引用计数减到0与内存接纳之间并不是立刻发生的,而是有一段距离的。凭据Python的机制,内存接纳只会在特定条件下执行。在占用内存比较小另有许多富足的情形下,往往是不会执行内存接纳的。由于Python在执行gc(garbage collection)的时刻也会stop the world,也就是暂停其他所有的义务,以是这是影响性能的一件事情,只会在有需要的时刻执行。

我们费这么大劲来先容Python中的内存机制,除了向人人科普一下这一块内容之外,更主要的一点是为了引出我们开发的时刻经常遇见的一种情形——循环引用。

循环引用

若是熟悉了Python的引用,来明白循环引用是异常容易的。说白了也很简朴,就是你的一个变量引用我,我的一个变量引用你。,吃鸡辅助,

我们来写一段简朴的代码,来看看循环引用:

class Test:

def __init__(self):

pass

if __name__ == '__main__':

a = Test()

b = Test()

a.t = b

b.t = a

若是你打个断点来看的话,会看到a和b之间的循环引用:

这里是无限睁开的,由于这是一个无限循环。无限循环并不会导致程序溃逃, 也不会带来太大的问题,它的问题只有一个,就是凭据前面先容的引用计数法,a和b的引用永远不能能为0。

也就是说凭据引用计数的原则,这两个变量永远不会被接纳,这显然是不合理的。虽然Python当中专门建立了机制来解决引用循环的问题,然则我们并不知道它什么时刻会被触发。

这个问题在Python当中异常普遍,尤其在我们实现一些数据结构的时刻。举个最简朴的例子就是树中的节点,就是引用循环的。由于父节点会存储所有的孩子,往往孩子节点也会存储父节点的信息。那么这就构成了引用循环。

class Node:

def __init__(self, val, father):

self.val = val

self.father = father

self.childs = []

弱引用

为领会决这个问题,Python中提供了一个叫做弱引用的观点。弱引用本质也是一种引用,然则它不会增添工具的引用计数。也就是说它不能保证它引用的工具一定不会被销毁,只要没有销毁,弱引用就可以返回预期的效果。

弱引用不用我们自己开发,这是Python当中集成的一个现成的模块weakref。

这个模块当中的方式许多,用法也许多,然则我们基本上用不到,一般来说最常用的就是ref方式。通过weakref库中的ref方式,可以返回工具的一个弱引用。我们照样来看个例子:

import weakref

class Test:

def __init__(self, name):

self.name = name

def __str__(self):

return self.name

if __name__ == '__main__':

a = Test('a')

b = Test('b')

a.t = weakref.ref(b)

b.t = weakref.ref(a)

print(a.t())

实在照样之前的代码,只是做了一点简朴的改动。一个是我们给Test加上了name这个属性,以及str方式。另一个是我们把直接赋值改成了使用weakref。

这一次我们再打断点进来看的话,就看不到无限循环的情形了:

ref返回的是一个获取引用工具的方式,而不是工具自己。以是我们想要获取这个工具的话,需要再把它当成函数挪用一下。

固然这样很贫苦,我们另有更好的设施,就是使用property注解。通过property注解,我们可以把weakref封装掉,这样在使用的时刻就没有感知了。

import weakref

class Test:

def __init__(self, name):

self.name = name

def __str__(self):

return self.name

@property

def node(self):

return None if self._node is None else self._node()

@node.setter

def node(self, node):

self._node = weakref.ref(node)

总结

引用和循环引用都是基于Python自己的机制,若是对这块机制不领会,很容易采坑。由于可能会泛起逻辑是对的,然则有一些意想不到的bug的情形。这种时刻,往往很难通过review代码或者是测试发现,这也是我们学习的瓶颈所在。很容易发现代码已经写得很熟练了,然则一些进阶的代码照样看不懂或者是写不出来,本质上就是由于缺少了对于底层的领会和认知。

循环引用的问题在我们开发代码的时刻还蛮常见的,尤其是涉及到树和图的数据结构的时刻。由于循环引用的关系,很有可能泛起被删除的树仍然占用着空间,内存不足的情形发生。这个时刻使用weakref就很有需要了。

今天的文章就到这里,原创不易,扫码关注我,获取更多精彩文章。

python做内存辅助_pubg辅助_Python一切皆是工具,但这和内存治理有什么关系?相关推荐

  1. python做大数据的框架_Python+大数据计算平台,PyODPS架构手把手教你搭建

    原文链接:http://click.aliyun.com/m/13965/ 在2016年10月的云栖社区在线培训上,来自阿里云大数据事业部的秦续业分享了<双剑合壁--Python和大数据计算平台 ...

  2. python做接口自动化测试仪器经销商_Python接口自动化测试的实现

    接口测试的方式有很多,比如可以用工具(jmeter,postman)之类,也可以自己写代码进行接口测试,工具的使用相对来说都比较简单,重点是要搞清楚项目接口的协议是什么,然后有针对性的进行选择,甚至当 ...

  3. python做一个登录注册界面_python做一个登录注册界面的方法

    python做一个登录注册界面的方法 发布时间:2020-08-21 10:37:05 来源:亿速云 阅读:111 作者:小新 这篇文章主要介绍python做一个登录注册界面的方法,文中介绍的非常详细 ...

  4. python界面开发工 跨平台具_python GUI开发常用工具

    Python最大的特点就在于她的快速开发功能.作为一种胶水型语言,python几乎可以渗透在我们编程过程中的各个领域.这里我简单介绍一下用python进行gui开发的一些选择.1.TkinterTki ...

  5. python做游戏用什么软件_Python 与游戏测试 (小工具篇)

    最近在TesterHome游戏测试群里,有时候会看到有童鞋问,游戏测试人员学了Python,可以干点什么. 很多童鞋初学Python,学习了语法和基础类库后,开始迷茫如何实际使用到工作中去,其实Pyt ...

  6. python做excel数据分析统计服_Python也能做到Excel那样,条件统计轻松解决工作需求...

    此系列文章收录在公众号中:数据大宇宙 > 数据处理 >E-pd 转发本文并私信我"python",即可获得Python资料以及更多系列文章(持续更新的) 经常听别人说 ...

  7. python做一个登录注册界面_Python 实现简单的登录注册界面

    Python 实现简单的登录注册界面 注意:编写代码之前需要导入很重要的包 import tkinter as tk import pickle from tkinter import message ...

  8. python 做表格分析难么_Python处理分析128张Excel表格竟然不到3秒?

    不少粉丝留言,想要了解怎么用Python提升处理数据的效率,或者说怎么用Python自动处理多张Excel表格,于是乎便有了本文. 这篇文章算是Python数据分析实战的第二个独立案例. 注:案例12 ...

  9. python做疫情数据分析的框架_Python制作新冠疫情世界地图

    目录 pyecharts模块 简介 Echarts 是一个由百度开源的数据可视化,凭借着良好的交互性,精巧的图表设计,得到了众多开发者的认可.而 Python 是一门富有表达力的语言,很适合用于数据处 ...

最新文章

  1. swift 方法的局部和外部参数名
  2. Altium Designer Exception ESocketError in module X2.EXE at 001B15CF (10107) on API 'Socket'
  3. 动态创建模板列并绑定数据(GridView,Repeater,DataGrid)
  4. 中英文对照 —— 经济、金融学、财务
  5. 一文理清HashMap的实现及细节
  6. LeetCode 363. 矩形区域不超过 K 的最大数值和(DP+set二分查找)
  7. ARC和MRC 兼容的单例模式
  8. 正确理解Python函数是第一类对象
  9. mysql typedefinition_深入浅出Mysql——基础篇
  10. 2021-06-09反射的类型方法
  11. proxmox VE 4.4 增加USB 重定向功能
  12. 泛泰A870L/K/S第三版官方4.4.2原来的系统卡刷机包 (愿自己主动ROOT)
  13. 关于公布2013年度局青年学术和技术带头人考评与增选结果的通知
  14. 双人贪吃蛇java 代码_贪吃蛇课设--个人博客
  15. 易捷行云新一代私有云平滑无感升级|轻运维之升级
  16. 反编译之脱去乐固加固的壳
  17. 证券业数据大集中及其风险控制分析
  18. 回味那些评论有时候也能受教--摘自双鱼座ROM之硬件评论
  19. 电子词典 C语言实现
  20. w8系统桌面没有计算机图标,不见了win8系统桌面图标怎么办

热门文章

  1. 机械臂绘图(绘制字母E)
  2. wps word修改内容未保存,如何恢复?
  3. Dockerfile中的copy命令
  4. URL、URI和URN
  5. 成都榆熙电子商务有限公司:优秀的创意图需要经过哪些打磨?
  6. IDEA的web项目文件夹添加项目标识(蓝色小点)
  7. AutoCAD调试模式下文字不显示
  8. Java static关键字你了解多少?
  9. 你了解Yaf 是什么嘛?
  10. 限时疯抢|¥1919元=高性能电脑+500京东卡!这波羊毛我撸爆!