Python类和对象–生命周期方法(对象生命周期,内存管理机制-存储,垃圾回收)

目录

1.生命周期概念

2.监听对象生命周期

3.内存管理机制

1.存储方面

2.垃圾回收方面

1>引用计数器

2>循环引用

3>垃圾回收


1.生命周期概念

指的是一个对象,从诞生到消亡的过程;

当一个对象被创建时,会在内存中分配相应的内存空间进行存储;

当这个对象不再使用,为了节约内存,就会把这个对象释放

涉及问题:

如何监听一个对象的生命过程?

Python是如何掌控一个对象的生命?

2.监听对象生命周期

__new__方法

当我们创建一个对象时,用于给这个对象分配内存的方法

通过拦截这个方法,可以修改对象的创建过程,比如:单例设计模式



class Person:
    def __new__(cls, *args, **kwargs):
        print("新建了一个对象,但是被拦截了")
    pass
 
# 新建了一个对象,但是被拦截了
# None
p=Person()
print(p)

__init__方法

初始化方法

当对象被创建时,会自动调用这个方法,会把p实例 传递给self,所以操作self就相当于操作外界的Person实例对象。

__del__方法

当对象被释放时,会自动调用这个方法

想要提前释放,就用del p



class Person:
    # def __new__(cls, *args, **kwargs):
    #     print("新建了一个对象,但是被拦截了")
    def __init__(self):
        print("初始化方法")
        self.name='sz'
    def __del__(self):
        print("这个对象被释放了")
 
# 初始化方法
# <__main__.Person object at 0x000001975F6B0A90>
# sz
# 这个对象被释放了
p=Person()
print(p)
print(p.name)

小案例



# Person类,打印一下,当前这个时刻,由Person类产生的实例,有多少个
# 创建一个实例,计数+1,如果删除一个实例,计数-1
class Person:
    __PersonCount=0
    def __init__(self):
        print("计数+1")
        Person.__PersonCount+=1
    def __del__(self):
        print("计数-1")
        self.__class__.__PersonCount-=1
    @classmethod
    def log(cls):
        print("当前个数%d"%Person.__PersonCount)
 
Person.personCount=100
p=Person()
p2=Person()
Person.log()
del p
del p2
Person.log()
 
# 计数+1
# 计数+1
# 当前个数2
# 计数-1
# 计数-1
# 当前个数0
3.内存管理机制
1.存储方面

1.在Python中万物皆对象,不存在基本数据类型。

0,1.2,True,False,”abc”,这些全都是对象。

2.所有对象,都会在内存中开辟一块空间进行存储,

会根据不同的类型以及内容,开辟不同的空间大小进行存储;

返回该空间的地址给外界接收(称为“引用”),用于后续对这个对象的操作,可通过id()函数获取内存地址(10进制),通过hex()函数可以查看对应的16进制地址。



class Person:
    pass
 
p=Person()
print(p)#<__main__.Person object at 0x0000021F732F2B90>
# print(id(p))#2334099712912
# print(hex(id(p)))#0x21f732f2b90
 
p2=Person()
#p和p2对象占用两块不同的内存空间
print(id(p),id(p2))#2523417750416 2523417473040

3.对于整数和短小的字符,Pthon会进行缓存;不会创建多个相同对象;



#1,2,3
num1=2
num2=2
#对于常用且不可改变的数据,python为了提高性能,会进行缓存,
# 在外界不论创建多少个相同对象,引用的都是同一个对象
print(id(num1),id(num2))#2120676540688 2120676540688

4.容器对象,存储的其他对象,仅仅是其他对象的引用,并不是其他对象本身;

2.垃圾回收方面
1>引用计数器

概念

一个对象,会记录着自身被引用的个数

每增加一个引用,这个对象的引用计数会自动+1

每减少一个引用,这个对象的引用计数会自动-1

对象被作为参数,传入到一个函数中,引用+2,因为函数对象内部有两个属性 引用着这个对象。



class Person:
    pass
p1= Person()#1
print(sys.getrefcount(p1))
 
def log(obj):
    print(sys.getrefcount(obj))
 
log(p1)#3
 
for attr in dir(log):
    print(attr,getattr(log,attr))

对象作为一个元素,存储在容器中,k=[p1]



class Person:
    pass
p1= Person()#1
print(sys.getrefcount(p1))#2
 
k=[p1]#2
print(sys.getrefcount(p1))#3

对象的别名被赋予新的对象,p1=123

查看引用计数

import sys

sys.getrefcount(对象),注意会大一



class Person:
    pass
p1= Person()#1
print(sys.getrefcount(p1))#2
 
p2=p1#2
print(sys.getrefcount(p1))#3
 
del p2#1
print(sys.getrefcount(p1))#2
 
del p1#0
print(sys.getrefcount(p1))#NameError: name 'p1' is not defined

2>循环引用

# 内存管理机制=引用计数器机制+垃圾回收机制;

# 当一个对象,如果被引用+1,删除一个引用-1,0就被自动释放;

# objgraph.count()可以查看,垃圾回收器 跟踪的类的对象个数;



import objgraph
class Person:
    pass
class Dog:
    pass
p=Person()
d=Dog()
 
print(objgraph.count("Person"))#1
print(objgraph.count("Dog"))#1
 
#删除p,d之后,对应的对象被释放掉
del p
del d
print(objgraph.count("Person"))#0
print(objgraph.count("Dog"))#0

3>垃圾回收

引用计数器的补充机制;

主要作用:从经历过“引用计数器机制”仍未被释放的对象中,找到“循环引用”,干掉相关对象;

底层机制(了解&难)

怎样找到“循环引用”?

如何提升查找“循环引用”的性能?



# 垃圾回收
import gc
 
# 新增的对象个数-消亡的对象个数,达到700时,才会触发垃圾检测
# 当0代检测10次后,才会触发0代和1代检测,当1代检测10次后,会触发0代,1代和2代 检测
print(gc.get_threshold())#(700, 10, 10)
 
gc.set_threshold(200,5,5)
 
print(gc.get_threshold())#(200, 5, 5)

垃圾回收机制(掌握&简单)

1.自动回收

触发条件

1》开启垃圾回收机制

gc.enable()开启垃圾回收机制(默认开启)

gc.disable()关闭垃圾回收机制

gc.isenabled()判断是否开启

并且

2》达到了垃圾回收的阈值

gc.get_threshold()获取自动回收阈值

gc.set_threshold(1000,5,5)设置自动回收阈值



# 自动回收
import gc
 
print(gc.isenabled())#True
# 关闭
gc.disable()
print(gc.isenabled())#False
# 开启
gc.enable()
print(gc.isenabled())#True
 
# 获取自动回收阈值
print(gc.get_threshold())#(700, 10, 10)
# 设置自动回收阈值
gc.set_threshold(1000,5,5)

2.手动回收



# 手动回收
import objgraph
import gc
# 1.定义了两个类
class Person:
    pass
class Dog:
    pass
 
# 2.根据这两个类,创建这两个实例对象
p=Person()
d=Dog()
 
# 3.让两个实例对象直接互相引用,造成循环引用
p.pet=d
d.master=p
 
# 4.尝试删除可到达引用之后,测试真实对象是否有被回收
del p
del d
 
# 5.通过“引用计数机制”无法回收,需要借助“垃圾回收机制”进行回收
gc.collect()
 
print(objgraph.count("Person"))#0
print(objgraph.count("Dog"))#0

注:

python2.x版本,一旦循环引用里面有一个类实现了__del__方法,就不会自动释放。



import objgraph
import gc
# 1.定义了两个类
class Person:
    def __del__(self):
        print("Person对象被释放了")
    pass
class Dog:
    def __del__(self):
        print("Dog对象被释放了")
    pass
 
p=Person()
d=Dog()
 
p.pet=d
d.master=p
 
del p
del d
 
gc.collect()
 
print(objgraph.count("Person"))#1
print(objgraph.count("Dog"))#1

解决这个问题有两种方法,一是预防,二是治疗
1》预防:避免循环引用的产生

2》治疗:手动破坏循环引用p.pet=None

强引用:能触发对象的引用计数+1的就是强引用;

弱引用:通过a能够使用真实对象,但是不会让对象的引用计数+1



# 预防:避免循环引用的产生
import objgraph
import gc
import weakref
class Person:
    def __del__(self):
        print("Person对象被释放了")
    pass
class Dog:
    def __del__(self):
        print("Dog对象被释放了")
    pass
 
p=Person()
d=Dog()
 
p.pet=d
# d.master=p
d.master=weakref.ref(p)#弱引用
 
del p
del d
#相当于没有产生循环引用,所以使用引用计数机制就可以释放掉,不需要这个方法
# gc.collect()
 
print(objgraph.count("Person"))#0
print(objgraph.count("Dog"))#0



# 治疗:手动破坏循环引用p.pet=None
import objgraph
import gc
import weakref
class Person:
    def __del__(self):
        print("Person对象被释放了")
    pass
class Dog:
    def __del__(self):
        print("Dog对象被释放了")
    pass
 
p=Person()
d=Dog()
 
p.pet=d
d.master=p
 
p.pet=None
del p
del d
 
# gc.collect()
 
print(objgraph.count("Person"))#0
print(objgraph.count("Dog"))#0

补充:一对多的引用



# 一对多的引用
import objgraph
import weakref
class Person:
    def __del__(self):
        print("Person对象被释放了")
    pass
class Dog:
    def __del__(self):
        print("Dog对象被释放了")
    pass
 
p=Person()
d1=Dog()
c1=Dog()
 
# p.pets={"dog": d1,"cat": c1}
# 一对多的引用,这样一个个写比较麻烦
# p.pets={"dog": weakref.ref(d1),"cat": weakref.ref(c1)}
#用weakref.WeakValueDictionary()方法
weakref.WeakValueDictionary({"dog": d1,"cat": c1})
 
# p.pet=d
d.master=p
 
del p
del d
 
print(objgraph.count("Person"))#0
print(objgraph.count("Dog"))#0
© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
猩的头像 - 鹿快
评论 抢沙发

请登录后发表评论

    暂无评论内容