pyth的垃圾回收机制
GC(垃圾回收)负责的主要任务
为新生成的对象分配内存
识别那些垃圾对象
从垃圾对象那回收内存
引用计数机制
Garbage collection(GC)模块的使用(垃圾回收)
现在的高级语言如java,c#等,都采用了垃圾收集机制,而不再是c,c++里用户自己管理维护内存的方式。自己管理内存极其自由,可以任意申请内存,但如同一把双刃剑,为大量内存泄露,悬空指针等bug埋下隐患。
对于一个字符串、列表、类甚至数值都是对象,且定位简单易用的语言,自然不会让用户去处理如何分配回收内存的问题。
python里也同java一样采用了垃圾收集机制,不过不一样的是: python采用的是引用计数机制为主,标记-清除和分代收集两种机制为辅的策略
import sys
# 创建时候1次,查看时候一次
a=[]
print('a被引用的次数是:{}'.format(sys.getrefcount(a)))
# 上面查看结束后会自动释放,所以创建1次,赋值1次,查看1次
b=a
print('a被引用的次数是:{}'.format(sys.getrefcount(a)))
print('b被引用的次数是:{}'.format(sys.getrefcount(b)))
# 被间接引用也算引用
c=b
d=c
print('a被引用的次数是:{}'.format(sys.getrefcount(a)))
引用机制的优点:
简单
实时性:一旦没有引用,内存就直接释放了。不用像其他机制需要等到特定时机。实时性还带来一个好处:处理回收内存的时间分摊到了平时
引用机制的缺点:
维护引用计数会消耗资源
循环引用就不适用了
list1 = []
list2 = []
list1.append(list2)
list2.append(list1)
list1与list2相互引用,如果不存在其他对象对它们的引用,list1与list2的引用计数也仍然为1,所占用的内存永远无法被回收,这将是致命的。对于如今的强大硬件,缺点1尚可接受,但是循环引用导致内存泄露,注定python还将引入新的回收机制。(标记清除和分代收集)
Python中的循环数据结构及引用计数
标记-清除机制
import psutil
import os
def showMemSize(tag):
pid=os.getpid() # 得到进程id
p=psutil.Process(pid) # 进程对象
info=p.memory_full_info() # 当前占用的内存信息
memory=info.uss/1024/1024 # 将字节格式转换为兆
print('{} memory used:{} MB'.format(tag,memory))
pass
# 验证循环引用的情况
def func():
showMemSize('初始化')
a=[i for i in range(10000000)]
b=[i for i in range(10000000)]
a.append(b)
b.append(a)
showMemSize('创建列表对象 a b 之后')
pass
func()
showMemSize('完成时候的')
import psutil
import os
import sys
def showMemSize(tag):
pid=os.getpid() # 得到进程id
p=psutil.Process(pid) # 进程对象
info=p.memory_full_info() # 当前占用的内存信息
memory=info.uss/1024/1024 # 将字节格式转换为兆
print('{} memory used:{} MB'.format(tag,memory))
pass
# 验证循环引用的情况
def func():
showMemSize('初始化')
a=[i for i in range(10000000)]
b=[i for i in range(10000000)]
a.append(b)
b.append(a)
showMemSize('创建列表对象 a b 之后')
print(sys.getrefcount(a))
print(sys.getrefcount(b))
del a
del b
pass
func()
showMemSize('完成时候的')
import psutil
import os
import gc # 导入垃圾回收机制
def showMemSize(tag):
pid=os.getpid() # 得到进程id
p=psutil.Process(pid) # 进程对象
info=p.memory_full_info() # 当前占用的内存信息
memory=info.uss/1024/1024 # 将字节格式转换为兆
print('{} memory used:{} MB'.format(tag,memory))
pass
# 验证循环引用的情况
def func():
showMemSize('初始化')
a=[i for i in range(10000000)]
b=[i for i in range(10000000)]
a.append(b)
b.append(a)
showMemSize('创建列表对象 a b 之后')
pass
func()
gc.collect() # 利用gc手动释放内存
showMemSize('完成时候的')
Python中gc模块
有三种情况会触发垃圾回收:(默认是开启垃圾回收的)
当gc模块的计数器达到阀值的时候,自动回收垃圾
调用gc.collect(),手动回收垃圾
程序退出的时候,python解释器来回收垃圾
python内存优化
小整数与大整数对象池