python 类 对象 内存_Python类对象的生命周期与内存管理机制

一、类对象的生命周期

什么是类对象的生命周期?

就是从对象创建 ----> 对象使用 ----> 对象销毁

废话少说,我们直接上代码来看

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的伙伴可以多多交流。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值