Python如何释放内存?

Python使用引用计数、分代算法回收垃圾,引用计数操作方法:

  1. 对象被引用一次,其计数器+1
  2. 对象被del,其计数器-1
  3. 对象的引用计数为0时候会被回收

python的__del__方法,类似java的finalize方法,会在对象被回收时执行

实验验证

实验1: 删除仅引用一次的对象

步骤:

  1. 创建一个class,重写__del__方法,打印信息
  2. 创建该类实例,然后把它del掉,观察是否有回收消息

预期:
对象被回收。

验证代码:

import time
class A:
    def __del__(self):
        print("A instance deleted")
a = A()
print("show globals after create a")
print(globals())  # 从全局对象中能找到A() 'a': <__main__.A object at 0x7f04de263af0>
del a # 
print("show globals after delete a")
print(globals())  # 这时全局对象中已经找不到对象A()了

time.sleep(1)

print("sleep end")
print(a)  # 无法访问引用

输出结果:

show globals after create a
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7f04de3de4c0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__cached__': None, 'time': <module 'time' (built-in)>, 'A': <class '__main__.A'>, 'a': <__main__.A object at 0x7f04de263af0>}
A instance deleted
show globals after delete a
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7f04de3de4c0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__cached__': None, 'time': <module 'time' (built-in)>, 'A': <class '__main__.A'>}
sleep end
Traceback (most recent call last):
  File "/testcode/mem.py", line 15, in <module>
    print(a)
NameError: name 'a' is not defined

结果分析:

调完del命令,__del__方法被执行,对象立即被删除(引用次数为0)。

实验2: 删除被多次引用的对象

步骤:

  1. 在上面那个用例的基础上,用多个引用引用A的对象
  2. 删除其中一个引用,观察对象是否被删除

预期:

删除一个引用,只是那个引用被删除了,但是对象不会被删除。也就是__del__方法不会被调用。

验证代码:

import time

class A:
    def __del__(self):
        print("delete instance of A")

a = A()

b = a
c = a
print("show globals after create a")
print(globals())
del a  # 执行完这一行之后对象没有被回收,因为并没有打印出 delete instance of A
print("show globals after delete a")
print(globals())  # 在globals 里面还能找到对象 'b': <__main__.A object at 0x7fe1ef0c2af0>, 'c': <__main__.A object at 0x7fe1ef0c2af0> ,对象还没有被回收

time.sleep(1)
print("after sleeping...")  # 打印完这句后 紧接着就打印了 delete instance of A ,也就是在 执行完 del b 和 del c 之后对象立即被回收了

del b
del c
print("show globals after delete b and c")  # 执行到此处之前对象已经被回收
print(globals())  # 打印的globals里已经找不到对象 A() 

输出结果:

show globals after create a
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7fe1ef23d4c0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': '/testcode/mem.py', '__cached__': None, 'time': <module 'time' (built-in)>, 'A': <class '__main__.A'>, 'a': <__main__.A object at 0x7fe1ef0c2af0>, 'b': <__main__.A object at 0x7fe1ef0c2af0>, 'c': <__main__.A object at 0x7fe1ef0c2af0>}
show globals after delete a
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7fe1ef23d4c0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': '/testcode/mem.py', '__cached__': None, 'time': <module 'time' (built-in)>, 'A': <class '__main__.A'>, 'b': <__main__.A object at 0x7fe1ef0c2af0>, 'c': <__main__.A object at 0x7fe1ef0c2af0>}
after sleeping...
delete instance of A
show globals after delete b and c
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x7fe1ef23d4c0>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': '/testcode/mem.py', '__cached__': None, 'time': <module 'time' (built-in)>, 'A': <class '__main__.A'>}

结论:回收对象的方法

编程时候,一个创建一个对象我们最好只设置一个引用指向它,当不需要这个对象时候用del删除这个引用就可以回收对应的对象了。

以上实验在Python 3.8.12 和 Python 3.7.7 验证过。

posted @ 2020-07-25 13:26  oaksharks  阅读(8528)  评论(0编辑  收藏  举报