Python中的垃圾收集
在 C 或 C++ 等语言中,程序员负责在堆上动态分配和释放内存。但在 Python 中,程序员无需预分配或释放内存。
Python 使用以下垃圾收集算法进行内存管理 -
-
引用计数
-
循环检测算法(循环引用)
引用计数
引用计数是一个简单的过程,当程序中不再引用被引用的对象时,该对象会被释放。
简而言之,当引用计数达到 时0
,该对象就会被释放(释放其分配的内存)。
让我们看看下面的例子 -
def calculate_sum(num1, num2):
total = num1 + num2
print(total)
在上面的例子中,我们有三个局部引用num1
,num2
和total
。这里与和total
不同,因为它只在块内部引用,因此其引用计数为 1,而在块外部引用,因此它们的引用计数可能不止 1。num1
num2
num1
num2
因此,当函数执行完毕后,引用计数total
减少到0
。因为它被垃圾收集器跟踪了。
垃圾收集器发现total
不再被引用(引用计数字段达到0
)并释放其分配的内存。
在函数外部声明的变量,即使函数执行完毕后也不会被销毁。
我们也可以使用del
语句手动删除变量。del
该语句会删除一个变量及其引用。当引用计数达到 时0
,它将被垃圾收集器回收。
引用计数算法也存在一些问题,例如循环引用 -
循环引用
当一个或多个对象相互引用时,就会发生引用循环。
如上图所示,list
对象 指向自身,并且object1
和object2
相互指向。此类对象的引用计数始终至少为1
。
让我们开始实际操作吧——
import gc
gc.set_debug(gc.DEBUG_SAVEALL)
lst = []
lst.append(lst)
lst_address = id(lst)
del lst
object_1 = {}
object_2 = {}
object_1['obj2'] = object_2
object_2['obj1'] = object_1
obj_address = id(object_1)
del object_1, object_2
在上面的例子中,该del
语句删除了变量及其对对象的引用。
让我们检查一下,它使用删除了变量gc.collect
,gc.collect
并将其保存到而gc.garbage
不是删除。
>>> gc.collect()
3
当我们删除一个变量时,我们只是删除了它的__main__
引用。现在我们根本无法访问lst
、object_1
和object_2
,但是这些变量仍然有 1 个引用,这意味着引用计数为 1,引用计数算法不会回收它。
检查参考计数如下-
import sys
print(sys.getrefcount(obj_address))
print(sys.getrefcount(lst_address))
2
2
# 1 from the variable and 1 from getrefcount
将此数字乘以 100 万个对象,您可能会遇到严重的内存泄漏问题。
对于这种引用循环,Python 有另一个专门用于发现和销毁循环引用的算法。它也是Python GC中唯一可控的部分。
概括
Python 有两种垃圾回收算法。一种用于处理引用计数,当引用计数达到上限时0
,它会移除对象并释放其分配的内存。另一种是循环检测算法,用于发现并销毁循环引用。
我希望您现在对 Python 中的垃圾收集算法有了一定的了解。
如果您有任何建议,请在评论中告诉我。
参考
https://rushter.com/blog/python-garbage-collector/
文章来源:https://dev.to/sharmapacific/garbage-collection-in-python-1d4g