Python 面向对象 内存管理机制

存储方面

  • 在 python 中万物皆对象,不存在基本数据类型
  • 所有数据类型,都会在内存中开辟一块空间进行存储。会根据不同的类型以及内容,开辟不同的空间大小进行存储。
    返回该空间的地址给外界接收(称为‘引用’),用于后续对这个对象的操作,
    可以通过id()函数获取内存地址(10进制)
    通过hex()函数可以查看对应的16进制地址
class Person(object):
    pass

p = Person()
print(p)
print(id(p))
print(hex(id(p)))

<main.Person object at 0x03DECE20>
64933408
0x3dece20

  • 对于整数和短小的字符,python会进行缓存,不会创建多个相同对象
num1 = 2
num2 = 2
print(id(num1), id(num2))

1430255552 1430255552

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

垃圾回收方面

引用计数器

概念

一个对象,会记录着自身被引用的个数,每增加一个引用,这个对象的引用计数会自动+1,每减少一个引用,这个对象的引用计数会自动-1

查看引用计数:

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

class Person(object):
    pass

p1 = Person() #1
print(sys.getrefcount(p1))

p2 = p1 #2
print(sys.getrefcount(p1))

del p2 #1
print(sys.getrefcount(p1))

del p1

2
3
2

引用计数器加减场景

  • 引用计数+1:
    • 对象被创建 P1 = Person()
    • 对象被引用 p2 = p1
    • 对象被作为参数,传入到一个函数中,+2
    • 对象作为一个元素,存储在容器中 l = [p1]
import sys

class Person(object):
    pass

p = Person() # 1
print(sys.getrefcount(p))

def log(obj):
    print(sys.getrefcount(obj))

log(p)

2
4

  • 引用计数-1
    • 对象的 别名被显示销毁 del p1
    • 对象的别名被赋予新的对象 p1 = 123
    • 一个对象离开它的作用域,一个函数执行完毕时
    • 对象所在的容器被销毁,或从容器中删除对象

循环引用

import sys
import objgraph

# 内存管理机制 = 引用计数机制 + 垃圾回收机制
# objgraph.count() 可以查看垃圾回收器,跟踪的对象个数

class Person(object):
    pass

class Dog(object):
    pass

p = Person()
d = Dog()

print(objgraph.count('Person'))
print(objgraph.count('Dog'))

p.pet = d
d.master = p

del p
del d

print(objgraph.count('Person'))
print(objgraph.count('Dog'))

1
1
1
1

垃圾回收

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

怎么找到循环引用?

  1. 收集所以的容器对象,通过一个双向链表进行引用。容器对象,可以引用其他对象的对象(列表,元组,字典)
  2. 针对于每一个容器对象,通过一个变量gc_refs来记录当前对应的引用计数
  3. 对于每一个容器对象,找到它引用的容器对象,并将这个容器对象的引用计数-1
  4. 经过步骤3之后,如果一个容器对象的引用计数为0,就代表可以被回收,肯定是循环引用导致它活到现在

分带回收

如果程序当中创建了很多个对象,而针对于每一个对象都要参与检测过程,则会非常的耗费性能,所以基于这个问题,产生了一种假设,越命大的对象,越长寿。假设一个对象10次检测都没干掉,那认定这个对象长寿,就减少检测频率
基于这种假设,设计了一套机制,分带回收。

  1. 默认一个对象被创建出来后,属于0代
  2. 如果经历这一代垃圾回收后,依然存活,则划分到下一代
  3. 垃圾回收周期顺序,0代垃圾回收一定次数,会触发0代和1代回收,1代垃圾回收一定次数,会触发2代回收

查看和设置相关参数:

import gc

print(gc.get_threshold())
gc.set_threshold(700, 10, 5)

垃圾回收时机

自动回收
触发条件:开启垃圾回收机制,达到了垃圾回收的阈值
gc.enable() 开启垃圾回收机制(默认开启)
gc.disable() 关闭垃圾回收机制
gc.isenabled() 判定是否开启

垃圾回收中,新增的对象的个数和释放的对象个数之差达到某个阈值
gc.get_threshold() 获取自动回收阈值
gc.set_threshold() 设置自动回收阈值

手动回收

import objgraph
import gc

class Person(object):
    pass

class Dog(object):
    pass

p = Person()
d = Dog()

p.pet = d
d.master = p

del p
del d

gc.collect()

print(objgraph.count('Person'))
print(objgraph.count('Dog'))

0
0

循环引用解决细节

弱引用

import objgraph
import gc
import weakref

class Person(object):
    def __del__(self):
        print('Person 对象被释放了')
    pass

class Dog(object):
    def __del__(self):
        print('Dog 对象被释放了')
    pass

p = Person()
d = Dog()

p.pet = d
d.master = weakref.ref(p)

del p
del d

# gc.collect()

print(objgraph.count('Person'))
print(objgraph.count('Dog'))

Person 对象被释放了
Dog 对象被释放了
0
0

删除关联

import objgraph
import gc
import weakref

class Person(object):
    def __del__(self):
        print('Person 对象被释放了')
    pass

class Dog(object):
    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'))
print(objgraph.count('Dog'))

Dog 对象被释放了
Person 对象被释放了
0
0

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值