一、类对象的生命周期
什么是类对象的生命周期?
就是从对象创建 ----> 对象使用 ----> 对象销毁
废话少说,我们直接上代码来看
class Person(object):
# 1.可以拦截对象的创建
def __new__(cls, *args, **kwargs):
print('__new__方法调用')
return super(Person, cls).__new__(cls, *args, **kwargs)
# 2.创建对象完成后会自动调用这个方法,并把实例传递给init方法
def __init__(self):
print('__init__初始化方法')
self.name = 'zb'
# 3.对象释放的时候自动调用
def __del__(self):
print('__del__对象释放')
p = Person() # 创建对象
del p # 删除对象
结果输出
__new__方法调用
__init__初始化方法
__del__对象释放
由此可见
创建对象时候先后调用new --> init
删除对象的时候 调用del
二、内存管理机制:
介绍内存管理之前我们先熟悉几个函数,之后我们会用到
print(id(p)) # 打印内存地址 10进制
print(hex(id(p))) # 打印内存地址 16进制
print(sys.getrefcount(p)) #查看对象的引用计数器的值
python 是万物皆对象,所有基本数据类型都是对象,但是常用数据类型的对象地址相同
num1 = 2
num2 = 2
print(hex(id(num1)), hex(id(num2)))
结果:0x1097fd070 0x1097fd070
内存管理包括2个机制并存引用计数器机制(性能高) + 垃圾回收机制(性能低,但是能解决循环引用问题)
2.1 引用计数器:计算对象被引用的次数是+1 取消引用-1
import sys
class Person(object):
pass
p1 = Person() # 引用计数器 = 1
print(sys.getrefcount(p1))
p2 = p1 # 引用计数器 = 2
print(sys.getrefcount(p1))
del p1 # 引用计数器 = 1
del p2 # 引用计数器 = 1
// 结果:2
3
注意:sys.getrefcount(p1)函数会自动将p1的引用计数器+ 1, 所以计算的时候要-1 引用计数 0 表示对象会被销毁
2.1.1 引用计数器+1 4个场景
A. 创建对象的时候 + 1; p = Person();
B . 对象赋值的时候 + 1; p2 = p
C. 对象作为函数的参数 + 2; func(p) 函数里面有2个引用
D. 对象作为某个对象的容器对象 + 1 ; a = [p]
2.1.2 引用计数器-1 4个场景
A. 对象被删除 -1; del p
B. 对象被重新赋值 -1; p = 123
C. 函数执行完毕,离开作用域-1;
D. 针对对象的容器对象的销毁 -1; del a
2.2 垃圾回收机制
引用计数机制虽然可以管理内存,但是不能解决循环引用问题,于是引用垃圾回收机制
objgraph.count('Person') # 查看类对象引用个数
垃圾回收机制底层原理
# 1、收集所有的"容器对象"(列表、字典、元祖、自定义对象),通过双向链表(集合)进行引用
# 2、针对每一个"容器对象",通过一个变量gc_refs来记录当前的引用计数器
# 3、对象每个'容器对象',找到他引用的'容器对象',并将这个'容器对象'的引用计数器 -1
# 4、经过步骤3之后,如果一个'容器对象'的引用计数器未0 就代表这个东西可以被回收啦,肯定是循环引用导致的
垃圾回收机制底层优化:分代回收 (优化垃圾回收性能)
垃圾检测触发机制:垃圾回收器 新增的对象个数 - 消亡的对象 达到一定的阈值才会触发垃圾回收
# 阈值设置
import gc
print(gc.get_threshold())
# (700, 10, 10) 默认当阈值大于700 检测一次 大于10 1代检测 大于10 2代加测
# 设置垃圾检测
gc.set_threshold(1000, 5, 5)
2.2.1 垃圾回收触发时机
A. 自动触发 : 先开启机制 后设置阈值
import gc
# 判断是否开启垃圾回收
isenable = gc.isenabled()
if isenable == False:
# 1. 开启回收
gc.enable()
#设置阈值
gc.set_threshold(500, 10, 10)
B.手动触发 : 解决循环引用
import objgraph # 引用计数器count
import gc # 垃圾回收机制
import weakref # 弱引用
class Person(object):
def __del__(self): // 实现了del 不能自动回收
print('Person对象被释放啦')
class Dog(object):
def __del__(self):
print('Dog对象被释放啦')
p = Person()
d = Dog()
# 循环引用
p.pet = d
d.master = p
# d.master = weakref.ref(p) #解决循环引用方式一 弱引用的应用
# p.pet = None # 解决循环引用方式二 指向None
del p
del d
# 解决循环引用方式三 垃圾回收机制手动回收
# gc.collect(1)
print(objgraph.count('Person'))
print(objgraph.count('Dog'))
总结
解决循环引用方案 :
1、weakref 弱引用 - 一个对象的弱引用 一对多的引用用需要弱引用字典
2、指向None 置空对象
3、 gc.collect(1) 垃圾回收机制回收
最后赠言
学无止境,学习Python的伙伴可以多多交流。