python中的垃圾回收(GC)机制

一、引用计数

Python 垃圾回收以引用计数为主,分代回收为辅。引用计数法的原理是每个对象维护一个ob_refcnt,用来记录对象被引用的次数,也就是用来追踪有多少个引用指向了对象,当发生以下四种情况的时候,对象的引用计数+1:

  • 对象被创建,比如:a = 14
  • 对象被引用,比如: b = a
  • 对象被作为参数,传给函数,比如:func(a)
  • 对象作为容器中的一个元素,比如:List = {a, ”a” , ”b”, 2}

与上述情况相对应,当发生以下四种情况时,对象的引用计数-1:

对象的别名被显式销毁,比如:del a
对象的别名被赋予新的对象,比如:a = 26
对象离开它的作用域,比如 func() 执行完毕时,函数里面的所有局部变量的引用计数都会减 1
将元素从容器中删除,或者容器被销毁
当对象的引用计数为 0 时,它将被 Python 虚拟机回收。

在 Python 中一切皆对象,它们的核心是 Py_Object 结构体,所有 Python 对象的头部都包含该结构:

// object.h
#define PyObject_HEAD
 _PyObject_HEAD_EXTRA
 Py_ssize_t ob_refcnt;
 struct _typeobject *ob_type;
​
typedef struct _object {
 PyObject_HEAD
} PyObject;

比如 int 类型的定义如下:

// intobj.h
typedef struct {
 PyObject_HEAD
 long ob_ival;
} PyIntObject;

简而言之,PyObject 是每个对象必有的内容,其中 ob_refcnt 是对象的引用计数。对象有新的引用时,它的 ob_refcnt 会增加;当对象的引用被删除时,ob_refcnt 会减少。当引用计数为 0 时,对象的生命周期就结束了。

// object.h
#define Py_INCREF(op) (
 _Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA
 ((PyObject*)(op))->ob_refcnt++)
​
#define Py_DECREF(op)
 do {
 if (_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA
 --((PyObject*)(op))->ob_refcnt != 0)
  _Py_CHECK_REFCNT(op)
 else
 _Py_Dealloc((PyObject *)(op));
 } while (0)

引用计数有很明显的优点:

  • 高效
  • 运行期没有停顿,即实时性:对象一旦没有引用,将直接被释放。实时性还带来一个好处是:处理回收内存的时间分摊到了平时
  • 对象有确定的生命周期
  • 易于实现

原始的引用计数法也有明显的缺点:

  • 维护引用计数消耗资源,维护引用计数的次数和引用赋值成正比
  • 无法解决循环引用的问题

比如:

list1 = []
list2 = []
list1.append(list2)
list2.append(list1)

为了解决这两个致命弱点,Python 又引入了以下两种 GC 机制。

二、标记-清除

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

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

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

标记清除算法作为 Python 的辅助垃圾回收技术,主要用于处理容器对象,比如 list、dict、tuple、instance 等,因为字符串、数值等原子类型的对象不可能造成循环引用问题。Python 使用双向链表将容器对象组织起来。不过这种简单粗暴的标记清除算法也有明显的缺点:清除非活动对象前,必须顺序扫描整个堆内存,哪怕只剩下小部分非活动对象,也要扫描所有对象。

三,分代回收

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

以上就是python中的GC机制的详细内容,更多关于python GC的资料请关注我们其它相关文章!

(0)

相关推荐

  • python的内存管理和垃圾回收机制详解

    简单来说python的内存管理机制有三种 1)引用计数 2)垃圾回收 3)内存池 接下来我们来详细讲解这三种管理机制 1,引用计数: 引用计数是一种非常高效的内存管理手段,当一个pyhton对象被引用时其引用计数增加1,当其不再被引用时引用计数减1,当引用计数等于0的时候,对象就被删除了. 2,垃圾回收(这是一个很重要知识点): ①  引用计数 引用计数也是一种垃圾回收机制,而且是一种最直观,最简单的垃圾回收技术. 在Python中每一个对象的核心就是一个结构体PyObject,它的内部有一个引

  • python垃圾回收机制(GC)原理解析

    这篇文章主要介绍了python垃圾回收机制(GC)原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 今天想跟大家分享的是关于python的垃圾回收机制,虽然本人这会对该机制没有很深入的了解, 但是本着热爱分享的原则,还是囫囵吞枣地坐下记录分享吧, 万一分享的过程中开窍了呢.哈哈哈. 首先还是做一下概述吧: 我们都知道, 在做python的语言编程中, 相较于java, c++, 我们似乎很少去考虑到去做垃圾回收,内存释放的工作, 其实是p

  • 理解Python垃圾回收机制

    一.垃圾回收机制 Python中的垃圾回收是以引用计数为主,分代收集为辅.引用计数的缺陷是循环引用的问题. 在Python中,如果一个对象的引用数为0,Python虚拟机就会回收这个对象的内存. #encoding=utf-8 __author__ = 'kevinlu1010@qq.com' class ClassA(): def __init__(self): print 'object born,id:%s'%str(hex(id(self))) def __del__(self): pr

  • Python的垃圾回收机制深入分析

    一.概述: Python的GC模块主要运用了"引用计数"(reference counting)来跟踪和回收垃圾.在引用计数的基础上,还可以通过"标记-清除"(mark and sweep)解决容器对象可能产生的循环引用的问题.通过"分代回收"(generation collection)以空间换取时间来进一步提高垃圾回收的效率. 二.引用计数 在Python中,大多数对象的生命周期都是通过对象的引用计数来管理的.从广义上来讲,引用计数也是一种垃

  • 如何快速理解python的垃圾回收机制

    一.先来说说为什么要有垃圾回收 解释器在执行到定义变量得语法时,会申请内存空间来存放变量得值,但是由于内存空间是有限得,所以这就涉及到了内存回收问题了,当一个变量值没有用了(简称垃圾),这种时候就应该回收掉这个变量值得内存空间. 二.那么什么是垃圾回收机制 垃圾回收机制(简称GC)是Python解释器自带一种机,专门用来回收不可用的变量值所占用的内存空间 三.为什么要用垃圾回收机制呢? 程序运行过程中会申请大量的内存空间,而对于一些无用的内存空间如果不及时清理的话会导致内存使用殆尽(内存溢出),

  • 详细分析Python垃圾回收机制

    引入 为什么要有垃圾回收机制 Python中的垃圾回收机制简称(GC),我们在程序的运行中会产生大量的变量用于保存数据,而有时候有些变量已经没有用了就需要被清理释放掉该变量所占据的内存空间.在一些较为低级的语言中(比如:C语言,汇编语言)对于内存空间的释放是需要编程人员来手动进行的,这种与底层硬件直接打交道的操作是十分的危险与繁琐的,而基于C语言开发而来的Python为了解决掉这种顾虑则自带了一种垃圾回收机制,从而让开发人员不必过分担心内存的使用情况而可以全身心的投入到开发中去. >>>

  • Python内存管理方式和垃圾回收算法解析

    概要 在列表,元组,实例,类,字典和函数中存在循环引用问题.有 __del__ 方法的实例会以健全的方式被处理.给新类型添加GC支持是很容易的.支持GC的Python与常规的Python是二进制兼容的. 分代式回收能运行工作(目前是三个分代).由 pybench 实测的结果是大约有百分之四的开销.实际上所有的扩展模块都应该依然如故地正常工作(我不得不修改了标准发行版中的 new 和 cPickle 模块).一个叫做 gc 的新模块马上就可以用来调试回收器和设置调试选项. 回收器应该是跨平台可移植

  • Python小白垃圾回收机制入门

    引用计数 Python默认的垃圾收集机制是"引用计数",每个对象维护了一个ob_ref字段.它的优点是机制简单,当新的引用指向该对象时,引用计数加1,当一个对象的引用被销毁时减1,一旦对象的引用计数为0,该对象立即被回收,所占用的内存将被释放.它的缺点是需要额外的空间维护引用计数,不过最主要的问题是它不能解决"循环引用". 什么是循环引用?A和B相互引用而再没有外部引用A与B中的任何一个,它们的引用计数虽然都为1,但显然应该被回收,例子: a = { } # a 的

  • Python中垃圾回收和del语句详解

    Python中的垃圾回收算法是采用引用计数, 当一个对象的引用计数为0时, Python的垃圾回收机制就会将对象回收 a = "larry" b = a larry这个字符串对象, 在第一行被贴了a标签后, 引用计数为1, 之后在第二行, 由贴上了b标签, 此时, 该字符串对象的引用计数为 a = "larry" b = a del a 注意: 在Python语言中, del语句操作某个对象的时候, 并不是直接将该对象在内存中删除, 而是将该对象的引用计数-1 &g

  • python中的垃圾回收(GC)机制

    一.引用计数 Python 垃圾回收以引用计数为主,分代回收为辅.引用计数法的原理是每个对象维护一个ob_refcnt,用来记录对象被引用的次数,也就是用来追踪有多少个引用指向了对象,当发生以下四种情况的时候,对象的引用计数+1: 对象被创建,比如:a = 14 对象被引用,比如: b = a 对象被作为参数,传给函数,比如:func(a) 对象作为容器中的一个元素,比如:List = {a, "a" , "b", 2} 与上述情况相对应,当发生以下四种情况时,对象

  • python语言开发垃圾回收机制原理教程

    目录 一.什么是垃圾回收机制 二.为什么要有垃圾回收机制 三.垃圾回收机制的原理 1.引用计数 直接引用 间接引用 2.栈区 / 堆区 3.总结 四.标记清除 1.循环引用问题(也叫交叉引用) 2.循环引用导致的结果 3.解决方法 : 清除-标记 五.分代回收 1.效率问题 2.解决方法 : 分代回收 分代 回收 总结 一.什么是垃圾回收机制 垃圾回收机制(简称GC), 解释器自带的一种机制 它是一种动态存储管理技术,自动释放不再被程序引用的对象所占用的内存空间 二.为什么要有垃圾回收机制 程序

  • python语法 之垃圾回收机制

    目录 一 引入 二.什么是垃圾回收机制? 三.为什么要用垃圾回收机制? 四.垃圾回收机制原理分析 4.1.什么是引用计数? 4.2.引用计数扩展阅读 4.2.1 标记-清除 4.2.2 分代回收 一 引入 ​ 解释器在执行到定义变量的语法时,会申请内存空间来存放变量的值,而内存的容量是有限的,这就涉及到变量值所占用内存空间的回收问题,当一个变量值没有用了(简称垃圾)就应该将其占用的内存给回收掉,那什么样的变量值是没有用的呢? ​ 由于变量名是访问到变量值的唯一方式,所以当一个变量值不再关联任何变

  • C#开发中的垃圾回收机制简析

    GC的前世与今生 虽然本文是以.NET作为目标来讲述GC,但是GC的概念并非才诞生不久.早在1958年,由鼎鼎大名的图林奖得主John McCarthy所实现的Lisp语言就已经提供了GC的功能,这是GC的第一次出现.Lisp的程序员认为内存管理太重要了,所以不能由程序员自己来管理.但后来的日子里Lisp却没有成气候,采用内存手动管理的语言占据了上风,以C为代表.出于同样的理由,不同的人却又不同的看法,C程序员认为内存管理太重要了,所以不能由系统来管理,并且讥笑Lisp程序慢如乌龟的运行速度.的

  • 基于java中stack与heap的区别,java中的垃圾回收机制的相关介绍

    #. 在java中有两类内存.分别称为stack(堆栈)和heap(堆). stack是程序内存空间,因此所有的基本类型和对象的引用是存在stack中. heap是java虚拟机储存对象的,它是一个巨大的内存,当你创造一个对象,java虚拟机把对象放入heap中,把创造的对象的地址放入stack中. 因此,基本类型.对象的引用储存在stack中:对象储存在heap中. #. java中的垃圾回收机制 当你new一个新的对象,java分配必需的内存.当你用完一个对象时,java的垃圾回收器为你把内

  • 谈谈JavaScript中的垃圾回收机制

    JavaScript 具有自动垃圾收集机制,也就是说,执行环境会负责管理代码执行过程中使用的内存. 在编写 JavaScript 程序时,开发人员不用再关心内存使用问题,所需内存的分配以及无用内存的回收完全实现了自动管理. 这种垃圾收集机制的原理其实很简单:找出那些不再继续使用的变量,然后释放其占用的内存.为此,垃圾收集器会按照固定的时间间隔(或代码执行中预定的收集时间), 周期性地执行这一操作. 具体到浏览器中的实现,则通常有两个策略,分别为标记清除和引用计数. 一.标记清除 JavaScri

  • go:垃圾回收GC触发条件详解

    版本: go version go1.13 darwin/amd64 在go源码runtime目录中找到gcTrigger结构体,就能看出大致调用的位置 GC调用方式 所在位置 代码 定时调用 runtime/proc.go:forcegchelper() gcStart(gcTrigger{kind: gcTriggerTime, now: nanotime()}) 分配内存时调用 runtime/malloc.go:mallocgc() gcTrigger{kind: gcTriggerHe

  • JavaScript中的垃圾回收与内存泄漏示例详解

    前言 程序的运行需要内存.只要程序提出要求,操作系统或者运行时就必须供给内存.所谓的内存泄漏简单来说是不再用到的内存,没有及时释放.为了更好避免内存泄漏,我们先介绍Javascript垃圾回收机制. 在C与C++等语言中,开发人员可以直接控制内存的申请和回收.但是在Java.C#.JavaScript语言中,变量的内存空间的申请和释放都由程序自己处理,开发人员不需要关心.也就是说Javascript具有自动垃圾回收机制(Garbage Collecation). 一.垃圾回收的必要性 下面这段话

  • c# 垃圾回收(GC)优化

    GC,Garbage Collect,中文意思就是垃圾回收,指的是系统中的内存的分配和回收管理.其对系统性能的影响是不可小觑的.今天就来说一下关于GC优化的东西,这里并不着重说概念和理论,主要说一些实用的东西.关于概念和理论这里只做简单说明,具体的大家可以看微软官方文档. 一.什么是GC GC如其名,就是垃圾收集,当然这里仅就内存而言.Garbage Collector(垃圾收集器,在不至于混淆的情况下也成为GC)以应用程序的root为基础,遍历应用程序在Heap上动态分配的所有对象[2],通过

  • 浅谈jvm中的垃圾回收策略

    java和C#中的内存的分配和释放都是由虚拟机自动管理的,此前我已经介绍了CLR中GC的对象回收方式,是基于代的内存回收策略,其实在java中,JVM的对象回收策略也是基于分代的思想.这样做的目的就是为了提高垃圾 回收的性能,避免对堆中的所有对象进行检查时所带来的程序的响应的延迟,因为jvm执行GC时,会stop the word,即终止其它线程的运行,等回收完毕,才恢复其它线程的操作.基于分代的思想是:jvm在每一次执行垃圾收集器时,只是对一小部分内存 对象引用进行检查,这一小部分对象的生命周

随机推荐