title: 对象引用与垃圾回收
copyright: true
top: 0
date: 2019-02-24 10:32:33
tags: 垃圾回收
categories: Python高阶笔记
permalink:
password:
keywords:
description: Python的核心,对象引用,可变性与垃圾回收机制。
这个世界很温柔,但它不喜欢我。
变量
Python作为静态语言,他的变量与其他语言的变量是不一样的。比如java中的变量你需要提前申明,定义数据类型,然后交给虚拟机执行。但是在python中的变量,本质上是一个指针,举个例子。
a = 1
python会做如下步骤:
- 在内存中申请一块内存空间存储一个int类型的对象
- 生成int类型的对象
- 最后把变量a指向数字1上面
- 可以把多个变量指向同一个对象
所以说,python中变量其实是一个指针,指向不同的对象。
is 与 ==
在深入类与对象-上中提起到is与==的区别:
这一开头就介绍了类的三大特性,类型(type),值(value),身份(id)
is:只要id相同,就返回True
==:只要value相同,就返回True
比如 1 == 1.0就返回True,1 is 1.0 就返回False。
注意了,这里变量都是不可变的类型,数字,字符串,浮点数都是不可变的(这里其实是python的小整形小字符串指向的都是同一个指针),所以使用is他们的id都是一样的,并且你定义一个类,实例化给a和b(不传入参数),他们的id也是一样的,如果实例化后传入参数,即使参数一样的,那他们的id也是不一样的。
但是对于list,set,dict这种可变的数据类型来说id也是不一样的。
垃圾回收
定义
python中的垃圾回收是以引用计数为主,标记-清除和分代收集为辅。
引用计数:python在内存中存储每个对象的引用计数,如果计数变成0,该对象就会消失,分配给该对象的内存就会释放出来。
标记-清除:一些容器对象,比如说list、dict、tuple、instance等可能会出现引用循环,对于这些循环,垃圾回收器会定时回收这些循环(对象之间通过引用(指针)连在一起,构成一个有向图,对象构成这个有向图的节点,而引用关系构成这个有向图的边)。
分代收集:python把内存根据对象存活时间划分为三代,对象创建之后,垃圾回收器会分配它们所属的代。每个对象都会被分配一个代,而被分配更年轻的代是被优先处理的,因此越晚创建的对象越容易被回收。
讲解
python的垃圾回收算法是引用计数为主,举个例子:
a = 100
b = a
这里python做了两步:
- 在100这个对象上,会有一个计数器,因为定义变量a=100,那么计数器的数值为1
- 然后又让b指向了a,本质上是b的指针也指向了100,这个时候100这个对象的计数器的数值为2
- 也就是说目前100这个对象的有两个变量指向他,计数器值是2
一开始在dict中介绍过,删除字典的某一对键值使用 del dict[‘user’],那么删除其他变量也是一样的,使用del即可。这个时候删除a
del a
这个时候100的计数器的值为1了,但是这个时候python并没有对100回收,因为之后当计数器的数值为0的时候才会回收100,这个时候你del a后,使用print(b)是没问题的,因为这个时候100这个对象还没有完全清除。
在一开始的魔法函数中,有__del__这个魔法函数,你定义的类中使用这个魔法函数,当你的类实例化运行完成后,需要回收垃圾的时候,就会调用这个del魔法函数,做你想要完成的事情。
内存池机制
Python提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。
1,Pymalloc机制。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。
2,Python中所有小于256个字节的对象都使用pymalloc实现的分配器,而大的对象则使用系统的malloc。
3,对于Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。