网易首页 > 网易号 > 正文 申请入驻

【蓝因子教育】用了Python,能多早下班就多早下班

0
分享至



我们写过C语言、C++的朋友都知道,我们的C语言是没有垃圾回收这种说法的。手动分配、释放内存都需要我们的程序员自己完成。不管是“内存泄漏” 还是野指针都是让开发者非常头疼的问题。所以C语言开发这个讨论得最多的话题就是内存管理了。但是对于其他高级语言来说,例如Java、C#、Python等高级语言,已经具备了垃圾回收机制。这样可以屏蔽内存管理的复杂性,使开发者可以更好的关注核心的业务逻辑。

对我们的Python开发者来说,我们可以当甩手掌柜。不用操心它怎么回收程序运行过程中产生的垃圾。但是这毕竟是一门语言的内心功法,难道我们甘愿一辈子做一个API调参侠吗?

1. 什么是垃圾?

当我们的Python解释器在执行到定义变量的语法时,会申请内存空间来存放变量的值,而内存的容量是有限的,这就涉及到变量值所占用内存空间的回收问题。

当一个对象或者说变量没有用了,就会被当做“垃圾“。那什么样的变量是没有用的呢?

a = 10000

当解释器执行到上面这里的时候,会划分一块内存来存储 10000 这个值。此时的 10000 是被变量 a 引用的

a = 30000

当我们修改这个变量的值时,又划分了一块内存来存 30000 这个值,此时变量a引用的值是30000。

这个时候,我们的 10000 已经没有变量引用它了,我们也可以说它变成了垃圾,但是他依旧占着刚才给他的内存。那我们的解释器,就要把这块内存地盘收回来。

2. 内存泄和内存溢出

上面我们了解了什么是程序运行过程中的“垃圾”,那如果,产生了垃圾,我们不去处理,会产生什么样的后果呢?试想一下,如果你家从不丢垃圾,产生的垃圾就堆在家里会怎么呢?

  1. 家里堆满垃圾,有个美女想当你对象,但是已经没有空间给她住了。
  2. 你还能住,但是家里的垃圾很占地方,而且很浪费空间,慢慢的,总有一天你的家里会堆满垃圾

上面的结果其实就是计算机里面让所有程序员都闻风丧胆的问题,内存溢出和内存泄露,轻则导致程序运行速度减慢,重则导致程序崩溃。

内存溢出:程序在申请内存时,没有足够的内存空间供其使用,出现 out of memory

内存泄露:程序在申请内存后,无法释放已申请的内存空间,一次内存泄露危害可以忽略,但内存泄露堆积后果很严重,无论多少内存,迟早会被占光

3. 引用计数

前面我们提到过垃圾的产生的是因为,对象没有再被其他变量引用了。那么,我们的解释器究竟是怎么知道一个对象还有没有被引用的呢?

答案就是:引用计数。python内部通过引用计数机制来统计一个对象被引用的次数。当这个数变成0的时候,就说明这个对象没有被引用了。这个时候它就变成了“垃圾”。

这个引用计数又是何方神圣呢?让我们看看代码

text = "hello,world"

上面的一行代码做了哪些工作呢?

  • 创建字符串对象:它的值是hello,world,
  • 开辟内存空间:在对象进行实例化的时候,解释器会为对象分配一段内存地址空间。把这个对象的结构体存储在这段内存地址空间中。

我们再来看看这个对象的结构体

```c++

typedef struct_object {

int ob_refcnt;

struct_typeobject *ob_type;

} PyObject;

熟悉c语言或者c++的朋友,看到这个应该特别熟悉,他就是结构体。这是因为我们Python官方的解释器是CPython,它底层调用了很多的c类库与接口。所以一些底层的数据是通过结构体进行存储的。看不懂的朋友也没有关系。这里,我们只需要关注一个参数:`ob_refcnt`这个参数非常神奇,它记录了这个对象的被变量引用的次数。所以上面 hello,world 这个对象的引用计数就是 1,因为现在只有text这个变量引用了它。**①变量初始化赋值:**```pythontext = "hello,world"



②变量引用传递:

new_text = text



③删除第一个变量:

del text



④删除第二个变量:

del new_text



此时 "hello,world" 对象的引用计数为:0,被当成了垃圾。下一步,就该被我们的垃圾回收器给收走了。



4. 引用计数如何变化

上面我们了解了什么是引用计数。那这个参数什么时候会发生变化呢?

4.1 引用计数加一的情况

  • 对象被创建
    a = "hello,world"
  • 对象被别的变量引用(赋值给一个变量)
    b = a
  • 对象被作为元素,放在容器中(比如被当作元素放在列表中)
    list = [] list.append(a)
  • 对象作为参数传递给函数
    func(a)

4.2 引用计数减一

  • 对象的引用变量被显示销毁
    del a
  • 对象的引用变量赋值引用其他对象
    a = "hello, Python" # a的原来的引用对象:a = "hello,world"
  • 对象从容器中被移除,或者容器被销毁(例:对象从列表中被移除,或者列表被销毁)
    del list
    list.remove(a)
  • 一个引用离开了它的作用域
    func(): a = "hello,world" return func() # 函数执行结束以后,函数作用域里面的局部变量a会被释放

4.3 查看对象的引用计数

如果要查看对象的引用计数,可以通过内置模块 sys 提供的方法去查看。

getrefcount

import sysa = "hello,world"print(sys.getrefcount(a))

注意:当使用某个引用作为参数,传递给 getrefcount() 时,参数实际上创建了一个临时的引用。因此,getrefcount() 所得到的结果,会比期望的多 1

5. 垃圾回收机制

其实Python的垃圾回收机制,我们前面已经说得差不多了。

Python通过引用计数的方法来说实现垃圾回收,当一个对象的引用计数为0的时候,就进行垃圾回收。但是如果只使用引用计数也是有点问题的。所以,python又引进了标记-清除分代收集两种机制。

Python采用的是引用计数机制为主,标记-清除和分代收集两种机制为辅的策略。

前面的引用计数我们已经了解了,那这个标记-清除跟分代收集又是什么呢?

5.1 引用计数机制缺点

Python语言默认采用的垃圾收集机制是“引用计数法 ”,该算法最早George E. Collins在1960的时候首次提出,50年后的今天,该算法依然被很多编程语言使用。

引用计数法:每个对象维护一个字段,用来记录该对象当前被引用的次数,每当新的引用指向该对象时,它的引用计数加1,每当该对象的引用失效时计数减1,一旦对象的引用计数为0,该对象立即被回收,对象占用的内存空间将被释放。

ob_refcnt

ob_refcnt

ob_refcnt

缺点:

  1. 需要额外的空间维护引用计数
  2. 无法解决循环引用问题

什么是循环引用问题?看看下面的例子

a = {"key":"a"} # 字典对象a的引用计数:1b = {"key":"b"} # 字典对象b的引用计数:1a["b"] = b # 字典对象b的引用计数:2b["a"] = a # 字典对象a的引用计数:2del a # 字典对象a的引用计数:1del b # 字典对象b的引用计数:1

看上面的例子,明明两个变量都删除了,但是这两个对象却没有得到释放。原因是他们的引用计数都没有减少到0。而我们垃圾回收机制只有当引用计数为0的时候才会释放对象。这是一个无法解决的致命问题。这两个对象始终不会被销毁,这样就会导致内存泄漏。

那怎么解决这个问题呢?这个时候 标记-清除 就排上了用场。标记清除可以处理这种循环引用的情况。

5.2 标记-清除策略

Python采用了标记-清除策略,解决容器对象可能产生的循环引用问题。

该策略在进行垃圾回收时分成了两步,分别是:

  • 标记阶段,遍历所有的对象,如果是可达的(reachable),也就是还有对象引用它,那么就标记该对象为可达;
  • 清除阶段,再次遍历对象,如果发现某个对象没有标记为可达,则就将其回收

这里简单介绍一下标记-清除策略的流程



可达(活动)对象:从root集合节点有(通过链式引用)路径达到的对象节点

不可达(非活动)对象:从root集合节点没有(通过链式引用)路径到达的对象节点

流程:

  1. 首先,从root集合节点出发,沿着有向边遍历所有的对象节点
  2. 对每个对象分别标记可达对象还是不可达对象
  3. 再次遍历所有节点,对所有标记为不可达的对象进行垃圾回收、销毁。

标记-清除是一种周期性策略,相当于是一个定时任务,每隔一段时间进行一次扫描。

并且标记-清除工作时会暂停整个应用程序,等待标记清除结束后才会恢复应用程序的运行。

5.3 分代回收策略

分代回收建立标记清除的基础之上,因为我们的标记-清除策略会将我们的程序阻塞。为了减少应用程序暂停的时间,Python 通过“分代回收”(Generational Collection)策略。以空间换时间的方法提高垃圾回收效率。

分代的垃圾收集技术是在上个世纪 80 年代初发展起来的一种垃圾收集机制。

简单来说就是:对象存在时间越长,越可能不是垃圾,应该越少去收集

Python 将内存根据对象的存活时间划分为不同的集合,每个集合称为一个代,Python 将内存分为了 3“代”,分别为年轻代(第 0 代)、中年代(第 1 代)、老年代(第 2 代)。

那什么时候会触发分代回收呢?

import gcprint(gc.get_threshold())# (700, 10, 10)# 上面这个是默认的回收策略的阈值# 也可以自己设置回收策略的阈值gc.set_threshold(500, 5, 5)

  • 700:表示当分配对象的个数达到700时,进行一次0代回收
  • 10:当进行10次0代回收以后触发一次1代回收
  • 10:当进行10次1代回收以后触发一次2代回收



5.4 gc模块

  • gc.get_count():获取当前自动执行垃圾回收的计数器,返回一个长度为3的列表
  • gc.get_threshold():获取gc模块中自动执行垃圾回收的频率,默认是(700, 10, 10)
  • gc.set_threshold(threshold0[,threshold1,threshold2]):设置自动执行垃圾回收的频率
  • gc.disable():python3默认开启gc机制,可以使用该方法手动关闭gc机制
  • gc.collect():手动调用垃圾回收机制回收垃圾

其实,既然我们选择了python,性能就不是最重要的了。我相信大部分的python工程师甚至都还没遇到过性能问题,因为现在的机器性能可以弥补。而对于内存管理与垃圾回收,python提供了甩手掌柜的方式让我们更关注业务层,这不是更加符合人生苦短,我用python的理念么。如果我还需要像C++那样小心翼翼的进行内存的管理,那我为什么还要用python呢?咱不就是图他的便利嘛。所以,放心去干吧。越早下班越好!

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
叙利亚反对派攻下阿勒颇!伊拉克民兵大举跨境,俄方加大马力支援

叙利亚反对派攻下阿勒颇!伊拉克民兵大举跨境,俄方加大马力支援

咊椿笔一汇
2024-12-03 10:32:08
突然宣布加息!12月3日,今日面对的四大消息冲击来袭!

突然宣布加息!12月3日,今日面对的四大消息冲击来袭!

风口招财猪
2024-12-03 08:52:43
中国突破冲压转子爆震发动机?网传H-20就是在等这种发动机!

中国突破冲压转子爆震发动机?网传H-20就是在等这种发动机!

星辰大海路上的种花家
2024-12-02 20:31:28
辛巴被立案调查!曾1亿赔付金“讨伐”三只羊,如今自己步入后尘

辛巴被立案调查!曾1亿赔付金“讨伐”三只羊,如今自己步入后尘

铁锤简科
2024-12-02 22:28:53
被恒大坑苦的几大装修老板,只有他提前醒悟,落袋14.6亿安全离场

被恒大坑苦的几大装修老板,只有他提前醒悟,落袋14.6亿安全离场

校长侃财
2024-12-01 11:06:25
阳痿是中年人的福报?哈佛大学:一个月21次或减少患癌风险

阳痿是中年人的福报?哈佛大学:一个月21次或减少患癌风险

番茄健康
2024-12-02 15:49:38
比亚迪与供应商的第三波内幕来了

比亚迪与供应商的第三波内幕来了

清晖有墨
2024-11-30 18:50:44
特斯拉最强FSD发布,不需人干预,上车到下车全程自动驾驶

特斯拉最强FSD发布,不需人干预,上车到下车全程自动驾驶

热点科技
2024-12-02 11:51:24
打蛇不打头!很多人都不懂,野外遇到蛇千万别打头

打蛇不打头!很多人都不懂,野外遇到蛇千万别打头

李律讲法
2024-11-25 22:40:03
药王谷“抗癌中心”调查:一种秘方治百癌,医馆部分人员无资质

药王谷“抗癌中心”调查:一种秘方治百癌,医馆部分人员无资质

新京报
2024-12-02 07:45:21
神秘重重?罗斯柴尔德家族成员葬身火海 此前低调隐居好莱坞

神秘重重?罗斯柴尔德家族成员葬身火海 此前低调隐居好莱坞

财联社
2024-12-02 11:52:09
当年轻人不再缴纳社保,一场危机正在凸显,不容忽视的社会现象

当年轻人不再缴纳社保,一场危机正在凸显,不容忽视的社会现象

社保小达人
2024-12-03 08:15:03
唐鹤德晒张国荣旧照反被骂,真面目被扒,深情人设崩塌?

唐鹤德晒张国荣旧照反被骂,真面目被扒,深情人设崩塌?

娱乐白名单
2024-12-02 10:07:12
宏远最新消息!杜锋官宣新小外,胡明轩战山西复出,吉伦沃特转正

宏远最新消息!杜锋官宣新小外,胡明轩战山西复出,吉伦沃特转正

多特体育说
2024-12-02 21:55:30
“老得慢”的女人,一般都有6个好习惯!如果你都有,那么恭喜你

“老得慢”的女人,一般都有6个好习惯!如果你都有,那么恭喜你

阿龙美食记
2024-11-24 19:36:27
癌症晚期的患者为啥会疼得死去活来呢?看到这张图你就明白了!

癌症晚期的患者为啥会疼得死去活来呢?看到这张图你就明白了!

科普先锋
2024-10-24 18:20:24
菲大批渔船恶意聚集中国岛礁,解放军直升机起飞在其头顶盘旋

菲大批渔船恶意聚集中国岛礁,解放军直升机起飞在其头顶盘旋

第一军情
2024-12-03 11:21:13
SpaceX据悉考虑出售内部股份,公司估值或大幅涨至约3500亿美元

SpaceX据悉考虑出售内部股份,公司估值或大幅涨至约3500亿美元

界面新闻
2024-12-03 07:15:12
“杨子荣”童祥苓逝世 张涵予王珮瑜等发文悼念

“杨子荣”童祥苓逝世 张涵予王珮瑜等发文悼念

封面新闻
2024-12-02 22:52:06
生擒菲士兵后,我海警杀向马德雷山号,提了个要求,菲方老实照办

生擒菲士兵后,我海警杀向马德雷山号,提了个要求,菲方老实照办

由史
2024-12-02 11:38:06
2024-12-03 12:08:49
原画在线课堂vv
原画在线课堂vv
一家有温度的原画教育机构
1187文章数 1关注度
往期回顾 全部

科技要闻

英特尔CEO基辛格“下课”,立即生效!

头条要闻

山西孝义一政府工程项目投资2.83亿 设计费就超500万

头条要闻

山西孝义一政府工程项目投资2.83亿 设计费就超500万

体育要闻

二轮秀场均20+ 他硬生生练成了CBA最强

娱乐要闻

王宝强被指忽悠小演员签“卖身契”

财经要闻

刘世锦:扩大消费需求要找准重点或痛点

汽车要闻

迎来拐点,阿维塔其实早就明牌了

态度原创

手机
游戏
家居
健康
公开课

手机要闻

华为官宣12月12日举行全球发布会,推出Mate X6

《无限暖暖》M站均分78分:进步的开放世界抽卡游戏

家居要闻

灵动合理 简约而不简单

花18万治疗阿尔茨海默病,值不值?

公开课

李玫瑾:为什么性格比能力更重要?

无障碍浏览 进入关怀版