Python 中的垃圾收集

关于垃圾收集及其在 Python 中如何完成的综合指南。

像许多其他流行的“垃圾收集”语言一样,Python 也提供自动垃圾收集。 尽管该过程是自动为您完成的,但了解基本机制肯定会让您受益匪浅。

什么是垃圾(在计算机世界中)?

在编程和/或计算机科学世界中,垃圾只不过是数据、对象或其他内存区域,不会在整个程序的未来计算中使用。 就像在现实世界中一样,垃圾是我们不再需要并扔掉的东西。 这同样适用于计算机和程序。 垃圾收集是为了识别不必要的数据或对象并将它们从内存中删除以释放内存,这样我们就不会面临任何内存泄漏。

既然您知道了垃圾是什么,那么让我们来了解一下垃圾收集是什么以及它是如何在 Python 中完成的。

Python 中的垃圾收集

正如我在内存引用计数课程中所讨论的,一旦引用计数变为 0,Python 内存管理器将丢弃该内存位置的对象并释放该内存槽。 但是,Python 的内存管理器不会处理循环引用。

什么是 Python 中的循环引用

在 Python 中,当两个对象相互指向时,就会发生循环引用,从而使引用计数彼此为 +1。 当 Python 中的两个对象相互持有引用时,称为循环引用或循环引用。 例如,当对象 A 的属性包含对对象 B 的属性的引用时,反之亦然。

请注意,对象可以属于相同或不同的类。

由于引用仍为 1,python 内存管理器不会释放内存位置。 而且,如果我们保持原样,就会发生内存泄漏。

在这种情况下,Python 的垃圾收集器就派上用场了。 Python 的垃圾收集器能够在整个代码中识别这些循环引用并清理它们。

什么是垃圾收集?

在计算机科学中,垃圾收集 (GC) 是一种自动内存管理形式。 垃圾收集器尝试回收由程序分配但不再被引用的内存——也称为垃圾。 — 维基百科.com

垃圾收集可以通过两种方式完成。 手动并通过垃圾收集器。 垃圾收集器是一种算法,当打开时,它会在您的程序中定期运行,并识别程序中不再使用的内存分配,并释放内存中的位置。 使用垃圾收集器可以省去手动垃圾收集的需要,让我们程序员的生活变得轻松。

在 Python 中,垃圾收集器可以通过 gc 模块访问。 我们可以导入它,然后与 gc 模块进行交互。 我们也可以修改它的行为。 Python 中的垃圾收集器默认开启。 但是您可以将其关闭。 我不建议将其关闭。 当且仅当您知道自己真正在做什么并且您 100% 确定您的程序没有进行任何循环引用时,才将其关闭。

让我们看一些代码来更多地理解这个概念。

from ctypes import c_long # to count the references
import gc # to interact with python garbage collector# wrapper function to count reference. Discussed in previous lecture
def ref_count(ref_id: int):
    return c_long.from_address(ref_id).value
# wrapper function to search for objects in garbage collector
def find_cir_ref(object_id):
    for obj in gc.get_objects():
        if id(obj) == object_id:
            return 'Object has been detected by the gc'
        else:
            return 'Not found'

上述包装函数将简化我们的测试工作。 现在让我们在 Python 中创建一个循环引用。

# Circular Reference in practiceclass A:
    def __init__(self):
        self.b = B(self)
        print(f'A - Self: {hex(id(self))}, B: {hex(id(self.b))}')class B:
    def __init__(self, another_object):
        self.a = another_object
        print(f'B - Self: {hex(id(self))}, A: {hex(id(self.a))}')

上面显示的代码,如果运行,将创建一个循环引用。 但是,如果您还记得,Python 的垃圾收集器默认情况下是打开的。 因此,它将立即识别并摆脱它。 因此,我们将首先关闭垃圾收集器以进行测试。

# to disable the garbage collector
gc.disable()my_var = A()
B - self: 0x248ce1a3a60, A: 0x248ce1a3670
A - self: 0x248ce1a3670, B: 0x248ce1a3a60 # your results may vary# as you can see, object B's "a" property is the same as the object A and object A's "b" property is the same as object B.a_id = id(my_var)
b_id = id(my_var.b)print(ref_count(a_id))
>>> 2 # since my_var and b are pointing to it
print(ref_count(b_id)
>>> 1 # since only a is pointing to itprint(find_cir_ref(a_id))
>>> Object has been detected by the gc
print(find_cir_ref(b_id))
>>> Object has been detected by the gc# the circular reference is successfully identified. Since the gc is disabled, it is not yet removed.my_var = Noneprint(ref_count(a_id))
>>> 1
print(ref_count(b_id))
>>> 1
# Even though, the initial variable has been reassigned, as you can see, both objects hold references to each other, leaving the reference count to 1.# now let's collect garbage manually.gc.collect()# now let's see if the detected circular reference is still in our programprint(find_cir_ref(a_id))
>>> Not found
print(find_cir_ref(b_id))
>>> Not found

正如您在上面的代码结果中看到的那样,Python 垃圾收集器足够聪明,可以识别和销毁循环引用并为我们节省数小时的调试时间。

总而言之,Python 的垃圾收集器是一个很好的打开它的工具。 它为我们节省了数小时的调试时间,并且非常方便。

如果您喜欢这篇文章并想了解更多有关 Python 高级概念的信息,请考虑关注我。 我将每天发表一篇关于高级 Python 概念的文章。

声明:本站部分文章内容及图片转载于互联 、内容不代表本站观点,如有内容涉及侵权,请您立即联系本站处理,非常感谢!

(0)
上一篇 2022年5月2日
下一篇 2022年5月2日

相关推荐