内存管理机制
存储方面
1.在Python中万物接对象
- 不存在基本数据类型
- 0,1.2,True,False,“abc”这些全都是对象
2.所有对象中,都会在内存中开辟一块空间进行存储
- 会根据不同的类型及其内容,开辟不同的空间大小进行存储
- 返回该空间的地址给外界接受(称为"引用"),用于后续对这个对象的操作
- 可通过id()函数获取内存地址(10进制)
- 通过hex()函数可以查看对应的16进制地址
class Person:
pass
p = Person
print(p)
print(id(p))
print(hex(id(p)))
#结果
<class '__main__.Person'>
2495730068704
0x245151aace0
- 3.对于整数和短小的字符,Python会进行缓存,不会创建对个相同对象
num1 = 2
num2 = 2
print(id(num1), id(num2))
#结果
1632086026576 1632086026576
4.容器对象,存储的其他对象,仅仅是其他对象的引用,并不是其他对象本身
垃圾回收方面
引用计数器
概念
- 一个对象,会记录着自身被引用的个数
- 每增加一个引用,这个对象的引用计数会自动+1
- 每减少一个引用,这个对象的引用计数会自动-1
查看引用计数
- import sys
- sys.getrefcount: 注意会大一(调用这个函数,会被当做一个参数传递给这个函数)
import sys
class Person:
pass
p1 = Person()
print(sys.getrefcount(p1))
p2 = p1
print(sys.getrefcount(p1))
del p2
print(sys.getrefcount(p1))
del p1
#结果
2
3
2
举例
引用计数的两个场景
- 引用计数+1场景
- 对象被创建:p1 = Person()
- 对象被引用:p1 = p2
- 对象被作为参数,传入到一个函数中
- 对象作为一个元素,存储在容器中:i = [P1]
- 引用计数-1场景
- 对象的别名被显示销毁:del p1
- 对象的别名被赋予新的对象:p1 = 123
- 一个对象刚离开他的作用域:一个函数执行完毕时,内部的局部变量关联的对象,她的引用对象会再次被释放
- 对象的容器被销毁,或从容器中删除对象
循环引用问题
内存泄露:一个对象在内存中无法使用,没有被释放的情况就是内存泄露
#objgraph.count()可以查看,垃圾回收器,跟踪的对象个数
import objgraph
class Person:
pass
class Dog:
pass
p = Person()
d = Dog()
print(objgraph.count("Person"))
print(objgraph.count("Dog"))
p.pet = d
d.master = p
#删除p,d之后,对应的对象是否被释放掉
del p
del d
print(objgraph.count("Person"))
print(objgraph.count("Dog"))
p.pet = d
d.master = p
del p
del d
#结果
1
1
1
垃圾回收
主要作用
从经历过"引用计数器机制"仍未被释放的对象中,找到"循环引用",干掉相关对象
底层机制
怎样找到“循环引用”?
如歌提升查找“循环引用”的性能?
查看以及修改机制配置参数
import gc
print(gc.get_threshold()) #查看
gc.set_threshold(200, 5, 5) #更改
#结果
(700, 10, 10) 每查10次0代的,查一次1代的,依次类推
垃圾回收时机
自动回收
import gc
gc.disable()
print(gc.isenabled())
gc.enable()
print(gc.isenabled())
print(gc.get_threshold())
gc.set_threshold(1000, 5, 5) #一般往大调,提升性能,垃圾回收耗时间
##
False
True
(700, 10, 10)
手动回收
import objgraph
import gc
#定义两个类
class Person:
pass
class Dog:
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