Python 中一切皆对象。因此,你所看到的一切变量,本质上都是对象的一个指针。
那么,怎么知道一个对象,是否永远都不能被调用了呢?
就是当这个对象的引用计数(指针数)为 0 的时候,说明这个对象永不可达,自然它也就成为了垃圾,需要被回收。
import os
import psutil
# 显示当前 python 程序占用的内存大小
def show_memory_info(hint):
pid = os.getpid()
p = psutil.Process(pid)
info = p.memory_full_info()
memory = info.uss / 1024. / 1024
print('{} memory used: {} MB'.format(hint, memory))
def func():
show_memory_info('initial')
a = [i for i in range(10000000)]
show_memory_info('after a created')
func()
show_memory_info('finished')
#该代码可在Ubuntu,Mac中运行,在Windows中运行会报错。
在上述代码中,会显示三次内存使用,第一次为初始时的,第二次的为运行func()函数,创建了a这个列表时,此时的数值会比第一次的大许多。第三次的func函数结束后,此时的数值应该是和第一次的差不多的,因为此时func函数中的a列表的作用域已经结束,所以他的内存也就自然而然的被自动释放了,而要是将a变量全局化的话
import os
import psutil
# 显示当前 python 程序占用的内存大小
def show_memory_info(hint):
pid = os.getpid()
p = psutil.Process(pid)
info = p.memory_full_info()
memory = info.uss / 1024. / 1024
print('{} memory used: {} MB'.format(hint, memory))
def func():
show_memory_info('initial')
global a
a = [i for i in range(10000000)]
show_memory_info('after a created')
func()
show_memory_info('finished')
此时第三次输出的数值便会和第二边的是一样的。因为将a全局化之后,他所占用的内存便不会被释放。
计数查询
如果是想要查看a这个变量具体的计数次数的话,我们可以使用sys库中的getrefcount()方法
import sys
a = []
print(sys.getrefcount(a))
此时运行的话,打印出的结果应该是2,这是因为sys.getrefcount(a)也会算作一次计数,但是如果是多次使用sys.getrefcount(a)的话,他的次数不会累加
import sys
a = []
print(sys.getrefcount(a))
print(sys.getrefcount(a))
如这样的话,两次打印的结果都是2,不会叠加
循环引用
如果有两个对象,它们互相引用,并且不再被别的对象所引用,那么它们应该被垃圾回收吗?
def func():
show_memory_info('initial')
a = [i for i in range(10000000)]
b = [i for i in range(10000000)]
show_memory_info('after a, b created')
a.append(b)
b.append(a)
func()
show_memory_info('finished')
如这段代码中,a与b相互引用,我们运行代码会发现此时是不会自动释放内存的,这时就需要我们自行手动释放内存,这时我们需要用的gc库中的collect()方法。
import gc
def func():
show_memory_info('initial')
a = [i for i in range(10000000)]
b = [i for i in range(10000000)]
show_memory_info('after a, b created')
a.append(b)
b.append(a)
func()
gc.collect()
show_memory_info('finished')
这样便能解决循环引用不能自行释放内存的问题。