📜  Python中的垃圾收集

📅  最后修改于: 2022-05-13 01:54:55.477000             🧑  作者: Mango

Python中的垃圾收集

Python 的内存分配和释放方法是自动的。与在 C 或 C++ 等语言中使用动态内存分配类似,用户不必预先分配或取消分配内存。
Python使用两种内存分配策略:

  • 引用计数
  • 垃圾收集

在Python 2.0 版本之前, Python解释器只使用引用计数来进行内存管理。引用计数通过计算一个对象被系统中其他对象引用的次数来工作。当对对象的引用被删除时,对象的引用计数会减少。当引用计数变为零时,对象被释放。前任-

Python
# Literal 9 is an object
b = 9
 
# Reference count of object 9
# becomes 0.
b = 4


Python
def create_cycle():
 
    # create a list x
    x = [ ]
 
    # A reference cycle is created
    # here as x contains reference to
    # to self.
    x.append(x)
  
create_cycle()


Python
x = []
x.append(l)
x.append(2)
 
# delete the list from memory or
# assigning object x to None(Null)
del x
# x = None


Python
# loading gc
import gc
 
# get the current collection
# thresholds as a tuple
print("Garbage collection thresholds:",
                    gc.get_threshold())


Python
# Importing gc module
import gc
 
# Returns the number of
# objects it has collected
# and deallocated
collected = gc.collect()
 
# Prints Garbage collector
# as 0 object
print("Garbage collector: collected",
          "%d objects." % collected)


Python
import gc
i = 0
 
# create a cycle and on each iteration x as a dictionary
# assigned to 1
def create_cycle():
    x = { }
    x[i+1] = x
    print x
 
# lists are cleared whenever a full collection or
# collection of the highest generation (2) is run
collected = gc.collect() # or gc.collect(2)
print "Garbage collector: collected %d objects." % (collected)
 
print "Creating cycles..."
for i in range(10):
    create_cycle()
 
collected = gc.collect()
 
print "Garbage collector: collected %d objects." % (collected)


字面量面值 9 是一个对象。对象 9 的引用计数在第 1 行中递增到 1。在第 2 行中,它的引用计数在取消引用时变为零。所以垃圾收集器会释放对象。
当对象的引用计数无法达到时,就会创建一个引用循环。涉及列表、元组、实例、类、字典和函数的引用循环很常见。创建引用循环的最简单方法是创建一个引用自身的对象,如下例所示:

Python

def create_cycle():
 
    # create a list x
    x = [ ]
 
    # A reference cycle is created
    # here as x contains reference to
    # to self.
    x.append(x)
  
create_cycle()

因为 create_cycle() 创建了一个引用自身的对象 x,所以当函数返回时对象 x 不会被自动释放。这将导致 x 正在使用的内存被保留,直到调用Python垃圾收集器。

使对象符合垃圾收集条件的方法

Python

x = []
x.append(l)
x.append(2)
 
# delete the list from memory or
# assigning object x to None(Null)
del x
# x = None

创建的列表的引用计数现在是两个。但是,由于无法从Python内部访问它并且不可能再次使用它,所以它被认为是垃圾。在当前版本的Python中,这个列表永远不会被释放。

循环的自动垃圾收集

因为引用循环需要计算工作才能发现,所以垃圾收集必须是计划的活动。 Python根据对象分配和对象释放的阈值安排垃圾收集。当分配数减去释放数大于阈值数时,垃圾收集器运行。可以通过导入 gc 模块并询问垃圾回收阈值来检查新对象的阈值( Python中称为第 0 代对象的对象):

Python

# loading gc
import gc
 
# get the current collection
# thresholds as a tuple
print("Garbage collection thresholds:",
                    gc.get_threshold())

输出:

Garbage collection thresholds: (700, 10, 10) 

这里,上述系统的默认阈值为 700。这意味着当分配次数与释放次数大于 700 时,自动垃圾收集器将运行。因此,释放大块内存的代码的任何部分都是运行手动垃圾收集的良好候选者。

手动垃圾收集

在程序执行期间手动调用垃圾收集器对于如何处理引用循环消耗的内存可能是一个好主意。
可以通过以下方式手动调用垃圾收集:

Python

# Importing gc module
import gc
 
# Returns the number of
# objects it has collected
# and deallocated
collected = gc.collect()
 
# Prints Garbage collector
# as 0 object
print("Garbage collector: collected",
          "%d objects." % collected)

输出:

('Garbage collector: collected', '0 objects.')

如果创建的周期很少,那么手动收集的工作原理:
例子:

Python

import gc
i = 0
 
# create a cycle and on each iteration x as a dictionary
# assigned to 1
def create_cycle():
    x = { }
    x[i+1] = x
    print x
 
# lists are cleared whenever a full collection or
# collection of the highest generation (2) is run
collected = gc.collect() # or gc.collect(2)
print "Garbage collector: collected %d objects." % (collected)
 
print "Creating cycles..."
for i in range(10):
    create_cycle()
 
collected = gc.collect()
 
print "Garbage collector: collected %d objects." % (collected)

输出:

Garbage collector: collected 0 objects.
Creating cycles...
{1: {...}}
{2: {...}}
{3: {...}}
{4: {...}}
{5: {...}}
{6: {...}}
{7: {...}}
{8: {...}}
{9: {...}}
{10: {...}}
Garbage collector: collected 10 objects.

执行手动垃圾收集有两种方法:基于时间的垃圾收集和基于事件的垃圾收集。

  1. 基于时间的垃圾收集很简单:垃圾收集器在固定的时间间隔后被调用。
  2. 基于事件的垃圾收集在事件发生时调用垃圾收集器。例如,当用户退出应用程序或应用程序进入空闲状态时。

参考

  • Python文档