专栏首页Python七号Python 是如何管理内存的?

Python 是如何管理内存的?

在 GitHub 看到一篇很不错的学习资料,其中提到 Python 是如何管理内存的,我看完后很有收获,如下:

原文[1]

当面试官问到这个问题的时候,一个展示自己的机会就摆在面前了。你要先反问面试官:“你说的是官方的CPython解释器吗?”。这个反问可以展示出你了解过 Python 解释器的不同的实现版本,而且你也知道面试官想问的是 CPython。当然,很多面试官对不同的 Python 解释器底层实现到底有什么差别也没有概念。所以,千万不要觉得面试官一定比你强,怀揣着这份自信可以让你更好的完成面试。

Python 提供了自动化的内存管理,也就是说内存空间的分配与释放都是由 Python 解释器在运行时自动进行的,自动管理内存功能极大的减轻程序员的工作负担,也能够帮助程序员在一定程度上解决内存泄露的问题。

以 CPython 解释器为例,它的内存管理有三个关键点:引用计数、标记清理、分代收集。

typedef struct _object {
    _PyObject_HEAD_EXTRA
    Py_ssize_t ob_refcnt;
    struct _typeobject *ob_type;
} PyObject;

引用计数:对于 CPython 解释器来说,Python 中的每一个对象其实就是 PyObject 结构体,它的内部有一个名为 ob_refcnt 的引用计数器成员变量。程序在运行的过程中 ob_refcnt 的值会被更新,并用 ob_refcnt 来反映有多少个变量引用到该对象。当对象的引用计数值为 0 时,它的内存就会被释放掉。

以下情况会导致引用计数加 1

  • 对象被创建
  • 对象被引用
  • 对象作为参数传入到一个函数中
  • 对象作为元素存储到一个容器中

以下情况会导致引用计数减 1

  • del语句显示删除对象引用
  • 对象引用被重新赋值其他对象
  • 一个对象离开它所在的作用域
  • 持有该对象的容器自身被销毁
  • 持有该对象的容器删除该对象

可以通过 sys 模块的 getrefcount 函数来获得对象的引用计数。引用计数的内存管理方式在遇到循环引用的时候就会出现致命伤,因此需要其他的垃圾回收算法对其进行补充。

标记清理

CPython使用了“标记-清理”(Mark and Sweep)算法解决容器类型可能产生的循环引用问题。该算法在垃圾回收时分为两个阶段:标记阶段,遍历所有的对象,如果对象是可达的(被其他对象引用),那么就标记该对象为可达;清除阶段,再次遍历对象,如果发现某个对象没有标记为可达,则就将其回收。

CPython 底层维护了两个双端链表,一个链表存放着需要被扫描的容器对象,姑且称之为链表 A,另一个链表存放着临时不可达对象,姑且称之为链表 B。为了实现“标记-清理”算法,链表中的每个节点除了有记录当前引用计数的 ref_count 变量外,还有一个 gc_ref 变量,这个 gc_refref_count 的一个副本,所以初始值为 ref_count 的大小。执行垃圾回收时,首先遍历链表 A 中的节点,并且将当前对象所引用的所有对象的 gc_ref1,这一步主要作用是解除循环引用对引用计数的影响。再次遍历链表 A 中的节点,如果节点的gc_ref值为0,那么这个对象就被标记为“暂时不可达”(GC_TENTATIVELY_UNREACHABLE)并被移动到链表B中;如果节点的gc_ref不为0,那么这个对象就会被标记为“可达”(GC_REACHABLE),对于“可达”对象,还要递归的将该节点可以到达的节点标记为“可达”;链表B中被标记为“可达”的节点要重新放回到链表A中。在两次遍历之后,链表 B 中的节点就是需要释放内存的节点。

分代回收

在循环引用对象的回收中,整个应用程序会被暂停,为了减少应用程序暂停的时间,Python 通过分代回收(空间换时间)的方法提高垃圾回收效率。分代回收的基本思想是:对象存在的时间越长,是垃圾的可能性就越小,应该尽量不对这样的对象进行垃圾回收。CPython将对象分为三种世代分别记为 012,每一个新生对象都在第 0 代中,如果该对象在一轮垃圾回收扫描中存活下来,那么它将被移到第 1 代中,存在于第 1 代的对象将较少的被垃圾回收扫描到;如果在对第 1 代进行垃圾回收扫描时,这个对象又存活下来,那么它将被移至第 2 代中,在那里它被垃圾回收扫描的次数将会更少。分代回收扫描的门限值可以通过 gc 模块的 get_threshold 函数来获得,该函数返回一个三元组,分别表示多少次内存分配操作后会执行 0 代垃圾回收,多少次 0 代垃圾回收后会执行 1 代垃圾回收,多少次 1 代垃圾回收后会执行 2 代垃圾回收。需要说明的是,如果执行一次 2 代垃圾回收,那么比它年轻的代都要执行垃圾回收。如果想修改这几个门限值,可以通过 gc 模块的 set_threshold 函数来做到。

最后的话

学习一门编程语言,一定要弄明白它是如何管理内存的,这不仅是如何应付面试的问题,更是如何更好的使用编程语言的基础。内存管理的一些算法设计,也有助于我们应对一些复杂的系统设计,学好它很有必要。

学习无止境,学的越多,就越觉得不知道的越多,但是学的越多,就越知道自己的边界,也就越不怕未知,这也是学习的意义。

留言讨论

参考资料

[1]

原文: https://github.com/jackfrued/Python-Interview-Bible/blob/master/Python面试宝典-基础篇-2020.md

本文分享自微信公众号 - Python七号(PythonSeven),作者:somenzz

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2021-08-16

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 在 Python 中是如何管理内存的?

    Python内存池:内存池的概念就是预先在内存中申请一定数量的,大小相等 的内存块留作备用,当有新的内存需求时,就先从内存池中分配内存给这个需求,不够了之后再申...

    宇宙之一粟
  • python是如何进行内存管理的

    python内部使用引用计数,来保持追踪内存中的对象,Python内部记录了对象有多少个引用,即引用计数,当对象被创建时就创建了一个引用计数,当对象不再需要时,...

    QQ1622479435
  • BAT面试题28:Python是如何进行内存管理的?

    多数情况下,引用计数比你猜测得要大得多。对于不可变数据(如数字和字符串),解释器会在程序的不同部分共享内存,以便节约内存。

    double
  • Linux 是如何管理内存的?

    Linux 内存管理模型非常直接明了,因为 Linux 的这种机制使其具有可移植性并且能够在内存管理单元相差不大的机器下实现 Linux,下面我们就来认识一下 ...

    cxuan
  • 物理内存是如何组织管理的

    内存管理,相比大家都听过。但是内存管理到底是做什么呢?这就得从计算机刚出来的时候说起。计算机刚出来的时候内存资源很紧张,只有几十K,后来慢慢的到几百K,到周后来...

    DragonKingZhu
  • Apache Flink 是如何管理好内存的?

    如今,许多用于分析大型数据集的开源系统都是用 Java 或者是基于 JVM 的编程语言实现的。最着名的例子是 Apache Hadoop,还有较新的框架,如 A...

    zhisheng
  • JVM是如何分配管理内存的?

    本文成文参考了《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)》和《Java虚拟机规范(Java SE 8版)》,这是两本难得的好书,推荐大家购买...

    一头小山猪
  • 如何管理内存

    内存是一种你不可以耗尽的珍贵资源。在一段时期里,你可以无视它,但最终你必须决定如何管理内存。

    硬核编程
  • 操作系统是如何管理物理内存的?

    1.抽象,即给每个程序逻辑地址空间2.保护,不同程序的地址空间互相隔离,无法越界访问3.共享,对于一些公共函数库,可以只在内存中存一份,其它程序引用这一个库即可...

    陆道峰
  • Python的内存管理

        一直以为用Python、java这样的语言就不在需要关心内存使用的问题,但事情还是发生了。     前一段时间需要写一个应用,需要将用户删除的记录在文...

    py3study
  • 什么是Python的 “内存管理机制”

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

    小灰
  • JavaScript如何工作:内存管理+如何处理4个常见的内存泄漏

    本中,我们将讨论另一个重要主题——内存管理,这是由于日常使用的编程语言越来越成熟和复杂,开发人员容易忽视这一问题。我们还将提供一些有关如何处理JavaScrip...

    Javanx
  • python中的内存分配与内存管理

    本文由腾讯云+社区自动同步,原文地址 https://stackoverflow.club/memory-control-in-python/

    羽翰尘
  • Python的内存管理机制

    任何编程语言都会有一个内存模型,以便管理为变量分配的内存空间。不同的编程语言,如C、C++、Java、C#,Python,它们的内存模型都是不相同的,本文将以现...

    蒙娜丽宁
  • 5.Block的内存管理 内存管理内存管理block的循环引用

    陈雨尘
  • JavaScript的工作原理:内存管理+如何处理4个常见的内存泄漏

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

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

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

    奋飛
  • Python深入06 Python的内存管理

    语言的内存管理是语言设计的一个重要方面。它是决定语言性能的重要因素。无论是C语言的手工管理,还是Java的垃圾回收,都成为语言最重要的特征。这里以Python语...

    Vamei
  • Python内存管理指南

    对于软件开发人员而言,了解内存管理很重要。随着Python在软件开发中得到广泛使用,编写高效的Python代码通常意味着需要编写内存高效使用的代码。随着大数据的...

    AI研习社

扫码关注云+社区

领取腾讯云代金券