Python内存管理机制和垃圾回收机制

内存管理机制有三种

  • 引用计数
  • 垃圾回收
  • 内存池

一、引用计数

引用计数是一种非常高效的内存管理手段,当一个python对象被引用时其引用计数增加一,当期不在引用时引用计数减少1,当引用计数等于0的时候对象就被删除了

二、垃圾回收(重点)

  • 引用计数
    引用计数也是一种垃圾回收机制,而且是一种最直接最简单的垃圾回收技术。
    在Python中每一个对象的核心就是一个结构体PyObject,它的内部有一个引用计数 ob_refcnt,当python的某个对象引用计数为0。就说明没有任何引用指向该对象,该对象就成为要被回收的垃圾了。
import sys


class Person(object):
    pass


p = Person()
p1 = p
print(sys.getrefcount(p))
p2 = p1
print(sys.getrefcount(p2))
p3 = p2
print(sys.getrefcount(p3))
class Person(object):
	"""
	循环引用
	"""
    pass
class Dog(object):
    pass
p = Person()
d = Dog()
p.pet = d
d.master = p
  • 标记清除
    『标记清除(Mark—Sweep)』算法是一种基于追踪回收(tracing GC)技术实现的垃圾回收算法。它分为两个阶段:第一阶段是标记阶段,GC会把所有的『活动对象』打上标记,第二阶段是把那些没有标记的对象『非活动对象』进行回收。那么GC又是如何判断哪些是活动对象哪些是非活动对象的呢?
    对象之间通过引用(指针)连在一起,构成一个有向图,对象构成这个有向图的节点,而引用关系构成这个有向图的边。从根对象(root object)出发,沿着有向边遍历对象,可达的(reachable)对象标记为活动对象,不可达的对象就是要被清除的非活动对象。根对象就是全局变量、调用栈、寄存器。
    Python内存管理机制和垃圾回收机制_第1张图片
    在上图中,我们把小黑圈视为全局变量,也就是把它作为root object,从小黑圈出发,对象1可直达,那么它将被标记,对象2、3可间接到达也会被标记,而4和5不可达,那么1、2、3就是活动对象,4和5是非活动对象会被GC回收。
    标记清除算法作为Python的辅助垃圾收集技术主要处理的是一些容器对象,比如list、dict、tuple,instance等,因为对于字符串、数值对象是不可能造成循环引用问题。Python使用一个双向链表将这些容器对象组织起来。不过,这种简单粗暴的标记清除算法也有明显的缺点:清除非活动的对象前它必须顺序扫描整个堆内存,哪怕只剩下小部分活动对象也要扫描所有对象。
  • 分代回收
    了解分代回收,首先了解下gc的阈值,所谓的gc阈值就是个临界点的值。
    随着你程序的运行,python解释器保持对新创建的对象,以及因为引用计数为0被释放的对象的追踪。从理论上说,创建==释放数量数量应该是这个样子,但循环引用肯定是循环>释放量,当创建数与释放数量的差值达到规定的阈值的时候,当当当当~分代回收机制就登场啦.
    分代回收思想将对象分为三代(generation 0,1,2)
    0代表幼年对象,
    1代表青年对象,
    2代表老年对象。
    根据弱代假说(越年轻的对象越容易死掉,老的对象通常会存活更久。)
    新生的对象被放入0代,如果该对象在第0代的一次gc垃圾回收中活了下来,那么它就被放到第1代里面(它就升级了)。如果第1代里面的对象在第1代的一次gc垃圾回收中活了下来,它就被放到第2代里面。
    从上一次第0代gc后,如果分配对象的个数减去释放对象的个数大于threshold0,那么就会对第0代中的对象进行gc垃圾回收检查。
    从上一次第1代gc后,如果第0代被gc垃圾回收的次数大于threshold1,那么就会对第1代中的对象进行gc垃圾回收检查。
    从上一次第2代gc后,如果第1代被gc垃圾回收的次数大于threshold2,那么就会对第2代中的对象进行gc垃圾回收检查。
    gc每一代垃圾回收所触发的阈值可以自己设置

三、内存池

  • python内存池机制呈现金字塔的形状, -1,-2层主要有操作系统进行操作
  • 第0层是C中的malloc, free等内存分配和释放函数进行操作
  • 第1层和第2层是内存池,有python接口函数,PyMem_Malloc函数实现,当对象小于256k的时由层直接分配内存
  • 第3层是最上层,也就是我们对python对象的直接操作
    Python在运行期间会大量地执行malloc和free的操作,频繁地在用户态和核心态之间进行切换,这将严重影响Python的执行效率。为了加速Python的执行效 率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。

四、调优手段

1.手动垃圾回收

import objgraph
import gc
import sys
class Person(object):
    pass
class Dog(object):
    pass
p = Person()
d = Dog()
p.pet = d
d.master = p
del p
del d
gc.collect()
print(objgraph.count("Person"))
print(objgraph.count("Dog"))

2.避免循环引用(手动解循环引用和使用弱引用)
3.调高垃圾回收阈值

你可能感兴趣的:(Python内存管理机制和垃圾回收机制)