乐趣区

关于程序员:Python-的内存管理与垃圾回收

本文首发自「慕课网」,想理解更多 IT 干货内容,程序员圈内热闻,欢送关注!

作者 | 慕课网精英讲师 朱广蔚

  1. 内存治理概述 1.1 手动内存治理在计算机倒退的晚期,编程语言提供了手动内存治理的机制,例如 C 语言,提供了用于调配和开释的函数 malloc 和 free,如下所示:#include <stdlib.h>

void *malloc(size_t size);
void free(void *p);
代码块 1234 函数 malloc 调配指定大小 size 的内存,返回内存的首地址函数 free 开释之前申请的内存程序员负责保障内存治理的正确性:应用 malloc 申请一块内存后,如果不再应用,须要应用 free 将其开释,示例如下:#include <stdlib.h>

void test()
{

void *p = malloc(10);

拜访 p 指向的内存区域;

free(p);

}

int main()
{

test();

}
代码块 123456789101112131415 应用 malloc(10) 调配一块大小为 10 个字节的内存区域应用 free§ 开释这块内存区域如果遗记开释之前应用 malloc 申请的内存,则会导致可用内存一直缩小,这种景象被称为“内存透露”,示例如下:#include <stdio.h>

include <stdlib.h>

void test()
{

void *p = malloc(10);

拜访 p 指向的内存区域;

}

int main()
{

while (1)
    test();

}
代码块 123456789101112131415 在函数 test 中,应用 malloc 申请一块内存然而应用结束后,遗记开释了这块内存在函数 main 中,循环调用函数 test() 每次调用函数 test(),都会造成内存透露最终,会耗尽所有的内存 1.2 主动内存治理在计算机倒退的晚期,硬件性能很差,为了最大水平的压迫硬件性能,编程语言提供了手动治理内存的机制。手动治理内存的机制的长处在于可能无效布局和利用内存,其毛病在于太繁琐了,很容易出错。随着计算机的倒退,硬件性能一直进步,这时候呈现的编程语言,例如:Java、C#、PHP、Python,则提供了主动治理内存的机制:程序员申请内存后,不须要再显式的开释内存,由编程语言的解释器负责开释内存,从根本上杜绝了“内存透露”这类谬误。在上面的 Python 程序中,在有限循环中一直的申请内存:class Person:

def __init__(self, name, age):
    self.name = name
    self.age = age

while True:

person = Person('tom', 13)

代码块 1234567 类 Person 蕴含两个属性:name 和 age 在 while 循环中,应用类 Person 生成一个实例 person 须要申请一块内存用于保留实例 person 的属性 Python 解释器运行这个程序时,发现实例 person 不再被援用后,会主动的开释 person 占用的空间。因而这个程序能够永远的运行上来,而不会把内存耗尽。2. 基于援用计数的内存治理 2.1 基本原理援用计数是一种最简略的主动内存管理机制:每个对象都有一个援用计数当把该对象赋值给一个变量时,对象的援用计数递增 1 援用计数的实例如下:A = object()
B = A
A = None
B = None
代码块 1234 在第 1 行,应用 object() 创立一个对象,变量 A 指向该对象对象的援用计数变动为 1 在第 2 行,变量 B 指向雷同的对象对象的援用计数变动为 2 在第 3 行,变量 A 指向 None 对象的援用计数变动为 1 在第 3 行,变量 B 指向 None 对象的援用计数变动为 0

从图中能够看出,当变量 A 和变量 B 都不再指向对象时,对象的援用计数变为 0,零碎检测到该对象成为废除对象,能够将此废除对象回收。2.2 长处和毛病援用计数的长处在于:实现简略零碎检测到对象的援用计数变为 0 后,能够及时的开释废除的对象解决回收内存的工夫摊派到了平时援用计数的毛病在于:保护援用计数耗费性能,每次变量赋值时,都须要保护保护援用计数无奈开释存在循环援用的对象上面是一个存在循环援用的例子:class Node:

def __init__(self, data, next):
    self.data = data
    self.next = next

node = Node(123, None)
node.next = node
node = None
代码块 12345678 在第 6 行,创建对象 node 对象 node 的 next 指向 None 此时对象 node 的援用计数为 1 在第 7 行,对象 node 的 next 指向 node 本身此时对象 node 的援用计数为 2 在第 7 行,对象 node 指向 None 此时对象 node 的援用计数为 1 对象 node 的 next 字段指向本身,导致:即便没有内部的变量指向对象 node,对象 node 的援用计数也不会变为 0,因而对象 node 就永远不会被开释了。3. 基于垃圾回收的内存治理 3.1 基本原理垃圾回收是目前支流的内存管理机制:通过一系列的称为“GC Root”的对象作为起始对象从 GC Root 登程,进行遍历最终将对象划分为两类:从 GC Root 能够达到的对象从 GC Root 无奈达到的对象从 GC Root 无奈达到的对象被认为是废除对象,能够被零碎回收。

在 Python 语言中,可作为 GC Roots 的对象次要是指全局变量指向的对象。从 GC Roots 登程,能够达到 object 1、object 2、object 3、object 4 从 GC Roots 登程,无奈达到 object 5、object 6、object 7,它们被断定为可回收的对象 3.2 长处和毛病垃圾回收的长处在于:能够解决存在循环援用的对象垃圾回收的毛病在于:实现简单进行垃圾回收时,须要扫描程序中所有的对象,因而须要暂停程序的运行。当程序中对象数量较多时,暂停程序的运行工夫过长,零碎会有显著的卡顿景象。4. Python 的内存管理机制 Python 的内存治理采纳了混合的办法:Python 应用援用计数来放弃追踪内存中的对象,当对象的援用计数为 0 时,回收该对象 Python 同时应用垃圾回收机制来回收存在有循环援用的对象上面的例子中,演示了 Python 的内存管理策略:class Circular:

def __init__(self):
    self.data = 0
    self.next = self

class NonCircular:

def __init__(self):
    self.data = 0
    self.next = None

def hybrid():

while True:
    circular = Circular()
    nonCircular = NonCircular()

hybrid()
代码块 12345678910111213141516 类 Circular,创立了一个蕴含循环援用的对象 self.next 指向本身,导致了循环援用类 Circular 的实例只能被垃圾回收机制开释类 NonCircular,创立了一个不蕴含循环援用的对象 self.next 指向 None,没有循环援用类 NonCircular 的实例能够援用计数机制开释在办法 hybrid 中在有限循环中,一直的申请 Circular 实例和 NonCircular 实例通过援用计数和垃圾回收机制,内存不会被耗尽,程序能够永远的运行上来。欢送关注「慕课网」,发现更多 IT 圈优质内容,分享干货常识,帮忙你成为更好的程序员!

退出移动版