存储方面
- 在 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
垃圾回收
主要作用:从经历过引用计数器机制任未被释放的对象中,找到循环引用,干掉相关对象
怎么找到循环引用?
- 收集所以的容器对象,通过一个双向链表进行引用。容器对象,可以引用其他对象的对象(列表,元组,字典)
- 针对于每一个容器对象,通过一个变量gc_refs来记录当前对应的引用计数
- 对于每一个容器对象,找到它引用的容器对象,并将这个容器对象的引用计数-1
- 经过步骤3之后,如果一个容器对象的引用计数为0,就代表可以被回收,肯定是循环引用导致它活到现在
分带回收
如果程序当中创建了很多个对象,而针对于每一个对象都要参与检测过程,则会非常的耗费性能,所以基于这个问题,产生了一种假设,越命大的对象,越长寿。假设一个对象10次检测都没干掉,那认定这个对象长寿,就减少检测频率
基于这种假设,设计了一套机制,分带回收。
- 默认一个对象被创建出来后,属于0代
- 如果经历这一代垃圾回收后,依然存活,则划分到下一代
- 垃圾回收周期顺序,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