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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,552评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,666评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,519评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,180评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,205评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,344评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,781评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,449评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,635评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,467评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,515评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,217评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,775评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,851评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,084评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,637评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,204评论 2 341

推荐阅读更多精彩内容

  • 生命周期的概念:世界上的万事万物都有它的生命周期,那么针对对象的生命周期到底是从哪里开始从哪里结束呢?当我们创建一...
    hello_我的哥阅读 7,662评论 0 5
  • python内存管理是通过引用计数来实现的。当对象的引用计数为0时,会被gc回收。 为了探索对象在内存的存储,我们...
    冬季恋歌1218阅读 1,641评论 0 2
  • 1.元类 1.1.1类也是对象 在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段。在Python中这...
    TENG书阅读 1,241评论 0 3
  • [TOC] 内存管理 一、托管堆基础 在面向对象中,每个类型代表一种可使用的资源,要使用该资源,必须为代表资源的类...
    _秦同学_阅读 3,766评论 0 3
  • 我还是长大了。 我还是只能把你留下来。 我们彼此相似,我们彼此又不同。 我走你走过的路,却会选择一种你也许没有尝试...
    lemo_8b6a阅读 215评论 1 0