专栏首页天澄技术杂谈剖析 Python 面试知识点(二)- 内存管理和垃圾回收机制
原创

剖析 Python 面试知识点(二)- 内存管理和垃圾回收机制

1. 内存管理

Python 中一切皆对象,对象又可以分为可变对象和不可变对象。二者可以通过原地修改,如果修改后地址不变,则是可变对象,否则为不可变对象,地址信息可以通过id()进行查看。

>>> a = 10
>>> id(a)
4339392960
>>> a =11
>>> id(a)
4339392992
>>> a = [1, 2]
>>> id(a)
4342877192
>>> a.append(3)
>>> a
[1, 2, 3]
>>> id(a)
4342877192

Python 有内存池机制,Pymalloc机制,用于对内存的申请和释放管理。先来看一下为什么有内存池:

当创建大量消耗小内存的对象时,c中频繁调用new/malloc会导致大量的内存碎片,致使效率降低。

内存池的概念就是预先在内存中申请一定数量的,大小相等的内存块留作备用,当有新的内存需求时,就先从内存池中分配内存给这个需求,不够了之后再申请新的内存。这样做最显著的优势就是能够减少内存碎片,提升效率。

查看源码,可以看到 Pymalloc 对于小的对象,Pymalloc会在内存池中申请空间,一般是少于236kb,如果是大的对象,则直接调用 new/malloc 来申请新的内存空间。

有了内存的创建,那就需要回收,垃圾回收机制,也是 Python 面试当中必问的一个知识点,接下来看看垃圾回收机制是什么?

2 垃圾回收机制

垃圾回收机制,Python 采用 GC 作为自动内存管理机制,GC要做的有2件事,一是找到内存中无用的垃圾对象资源,二是清除找到的这些垃圾对象,释放内存给其他对象使用。

如何实现上述2点了,Python 采用了 引用计数 为主, 标志清除和分代回收 为辅测策略。

2.1 引用计数

查看源码,每一个对象,在源码里就是一个结构体表示,都会有一个计数字段.

typedef struct_object {
 int ob_refcnt;
 struct_typeobject *ob_type;
} PyObject;

PyObject是每个对象必有的内容,其中ob_refcnt就是做为引用计数。当一个对象有新的引用时,它的ob_refcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少。 一旦对象的引用计数为0,该对象立即被回收,对象占用的内存空间将被释放。

此算法的优点和缺点都是非常明显的: 优点:

  • 简单
  • 实时性:一旦没有引用,内存就直接释放了。不用像其他机制等到特定时机。

缺点:

  • 需要额外的空间维护引用计数。
  • 不能解决对象的循环引用。(主要缺点)

接下来说一下什么是循环引用:

A和B相互引用而且没有外部引用A与B中的任何一个。也就是对象之间互相应用,导致引用链形成一个环。

>>>>>>a = { } #对象A的引用计数为 1
>>>b = { } #对象B的引用计数为 1
>>>a['b'] = b  #B的引用计数增1
>>>b['a'] = a  #A的引用计数增1
>>>del a #A的引用减 1,最后A对象的引用为 1
>>>del b #B的引用减 1, 最后B对象的引用为 1

执行 del 后,A、B对象已经没有任何引用指向这两个对象,但是这两个对象各包含一个对方对象的引用,虽然最后两个对象都无法通过其它变量来引用这两个对象了,这对GC来说就是两个非活动对象或者说是垃圾对象。理论上是需要被回收的。 按上面的引用计数原理,要计数为0才会回收,但是他们的引用计数并没有减少到零。因此如果是使用引用计数法来管理这两对象的话,他们并不会被回收,它会一直驻留在内存中,就会造成了内存泄漏(内存空间在使用完毕后未释放)。

为了解决对象的循环引用问题,Python 引入了标记清除和分代回收两种GC机制。

2.2 标记清除

标记清除主要是解决循环引用问题。

标记清除算法是一种基于追踪回收(tracing GC)技术实现的垃圾回收算法。 它分为两个阶段:第一阶段是标记阶段,GC会把所有的 活动对象 打上标记,第二阶段是把那些没有标记的对象 非活动对象 进行回收。那么GC又是如何判断哪些是活动对象哪些是非活动对象的呢?

对象之间通过引用(指针)连在一起,构成一个有向图,对象构成这个有向图的节点,而引用关系构成这个有向图的边。从根对象(root object)出发,沿着有向边遍历对象,可达的(reachable)对象标记为活动对象,不可达的对象就是要被清除的非活动对象。根对象就是全局变量、调用栈、寄存器。

在上图中,我们把小黑圈视为全局变量,也就是把它作为root object,从小黑圈出发,对象1可直达,那么它将被标记,对象2、3可间接到达也会被标记,而4和5不可达,那么1、2、3就是活动对象,4和5是非活动对象会被GC回收。

标记清除算法作为 Python 的辅助垃圾收集技术主要处理的是容器对象(container,上面讲迭代器有提到概念),比如list、dict、tuple等,因为对于字符串、数值对象是不可能造成循环引用问题。Python使用一个双向链表将这些容器对象组织起来。

Python 这种简单粗暴的标记清除算法也有明显的缺点:清除非活动的对象前它必须顺序扫描整个堆内存,哪怕只剩下小部分活动对象也要扫描所有对象。

2.3 分代回收

分代回收是一种以空间换时间的操作方式。

Python将内存根据对象的存活时间划分为不同的集合,每个集合称为一个代,Python将内存分为了3“代”,分别为年轻代(第0代)、中年代(第1代)、老年代(第2代),他们对应的是3个链表,它们的垃圾收集频率与对象的存活时间的增大而减小。新创建的对象都会分配在年轻代,年轻代链表的总数达到上限时,Python垃圾收集机制就会被触发,把那些可以被回收的对象回收掉,而那些不会回收的对象就会被移到中年代去,依此类推,老年代中的对象是存活时间最久的对象,甚至是存活于整个系统的生命周期内。同时,分代回收是建立在标记清除技术基础之上。

分代回收同样作为Python的辅助垃圾收集技术处理容器对象

『剖析Python面试知识点』完整内容请查看 :

https://gitbook.cn/gitchat/activity/5c8e364590020a6262806c8d

更多精彩文章请关注公众号: 『天澄技术杂谈』

天澄技术杂谈

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 剖析 Python 面试知识点(一): 魔法方法、闭包/自省、装饰器/生成器

    在Python中用双下划线__包裹起来的方法被成为魔法方法,可以用来给类提供算术、逻辑运算等功能,让这些类能够像原生的对象一样用更标准、简洁的方式进行这些操作。...

    天澄技术杂谈
  • 『MySQL』深入理解事务的来龙去脉

    距离上一篇MySQL的文章已经过去一个月了,终于有时间来写写关于MySQL的事务了。本文内容默认是针对 MySQL InnoDB 引擎。

    天澄技术杂谈
  • 『Microservices & Nameko』Python 微服务实践

    微服务最近一二年非常热门,谈论也比较多,简单的说,微服务将单一应用程序作为由众多小型服务构成之套件加以开发的方式,其中各项服务都拥有自己的进程并利用轻量化机制(...

    天澄技术杂谈
  • 【iOS面试粮食】内存管理

    iOS的内存管理一般指的是OC对象的内存管理,因为OC对象分配在堆内存,堆内存需要程序员自己去动态分配和回收;基础数据类型(非OC对象)则分配在栈内存中,超过作...

    iOS_林夕
  • 闲谈Android中的内存泄漏

    在长久以来的 Android 开发过程中,内存泄漏一直是一个比较头疼的问题。内存泄漏会导致应用卡顿,用户体验不佳,甚至会造成应用崩溃的严重后果。所以如何科学地进...

    俞其荣
  • JavaScript的工作原理:内存管理+如何处理4个常见的内存泄漏

    这篇文章将讨论日常编程中另一个复杂且容易被忽视的问题 — 内存管理。其中还提供了一些关于如何处理 JavaScript 内存泄露的提示,来防止导致内存泄漏以及不...

    奋飛
  • 内存泄露从入门到精通三部曲之基础知识篇

    1 首先以一个内存泄露实例来开始本节基础概念的内容: 实例1:(单例导致内存对象无法释放而泄露) ? ? 可以看出ImageUtil这个工具类是一个单例,并引...

    腾讯Bugly
  • 什么是Python的 “内存管理机制”

    Python作为一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言,与大多数编程语言不同,Python中的变量无需事先申明,变量无需指定类型,程序员无...

    小灰
  • Java虚拟机之垃圾收集器(5)

    (1)Java 内存运行时区域的各个部分,其中程序计数器、虚拟机栈、本地方法栈三个区域随线程而生,随线程而灭;栈中的栈帧随着方法的进入和退出而有条不紊地执行着出...

    Java后端技术
  • Android内存泄漏分享

    内容概述 内存泄漏和内存管理相关基础。 Android中的内存使用。 内存分析工具和实践。 以下内容不考虑非引用类型的数据,或者将其等同为对应的引用类型看待——...

    用户1172465

扫码关注云+社区

领取腾讯云代金券