python的垃圾回收机制:内存管理的幕后英雄

liftword11小时前技术文章2

一、什么是垃圾回收机制?

在Python程序运行过程中,会不断创建各种对象,如列表、字典、类实例等。当这些对象不再被使用时,就成了 “垃圾”,占用的内存空间需要被释放,以便后续程序使用。垃圾回收机制(Garbage Collection,简称 GC)是Python中自动管理内存、回收 “垃圾” 对象的一套机制。

二、Python 垃圾回收核心原理

1. 引用计数

原理:Python 为每个对象维护一个引用计数,记录该对象被引用的次数。当对象被创建时,引用计数为 1;每次被引用(如赋值给变量、作为参数传递等),引用计数加 1;当引用失效(如变量被删除、函数执行结束),引用计数减 1。当引用计数为 0 时,对象占用的内存会被立即回收。

案例

a = [1, 2, 3] # 对象[1, 2, 3]的引用计数为1
b = a # 对象[1, 2, 3]的引用计数变为2
del a # 对象[1, 2, 3]的引用计数减为1
b = None # 对象[1, 2, 3]的引用计数变为0,内存被回收

2. 标记 - 清除

原理:对于循环引用(即对象之间相互引用,导致引用计数无法降为0)的情况,Python 采用标记 - 清除算法。首先从根对象(如全局变量、栈上的变量等)开始 “标记” 所有可达的对象,这些对象是程序仍在使用的;然后扫描整个内存空间,清除所有未被标记的对象,即 “垃圾” 对象。

案例

class Node:
	def __init__(self):
		self.next = None
a = Node()
b = Node()
a.next = b
b.next = a # a和b循环引用
del a
del b # 此时a和b的引用计数仍为1,通过标记 - 清除算法回收内存

3. 分代回收

原理:Python将对象分为三代,根据对象存活时间的不同进行管理。新创建的对象位于第0代,当第0代对象经过一定次数的垃圾回收后仍存活,会被移到第1代;同理,第1代对象经过多次回收存活后,会移到第2代。垃圾回收时,优先回收第0代对象,因为新创建的对象更有可能很快变成 “垃圾”,这样可以提高回收效率。

三、与垃圾回收相关的函数及案例

1. sys.getrefcount()

功能:获取对象的引用计数。注意,调用该函数时会临时增加一次引用计数(因为函数调用本身也是对对象的引用),所以返回值比实际引用计数多 1。

案例

import sys
a = [10, 20]
print(sys.getrefcount(a)) # 输出比实际引用计数多1
b = a
print(sys.getrefcount(a)) # 引用计数增加

2. gc.get_threshold() 和 gc.set_threshold()

功能

  • gc.get_threshold():获取分代回收中各代对象的回收阈值,返回一个三元组,分别对应第0代、第1代、第2代的阈值。
  • gc.set_threshold(threshold0[, threshold1[, threshold2]]):设置分代回收中各代对象的回收阈值。

案例

import gc
# 获取当前回收阈值
print(gc.get_threshold())
# 设置新的回收阈值
gc.set_threshold(700, 10, 10)
print(gc.get_threshold())

3. gc.collect()

功能:手动触发垃圾回收,无论当前对象的引用计数和代龄如何,立即执行垃圾回收操作。

案例

import gc
class BigObject:
	def __init__(self):
		self.data = [i for i in range(1000000)]

# 创建对象,占用大量内存
obj = BigObject()
del obj # 此时对象成为垃圾,但不一定立即回收
# 手动触发垃圾回收
gc.collect()

四、循环引用场景下查看对象引用情况

1.先不构建循环引用

class Node:
    def __init__(self):
        self.next = None
#实例化Node对象
a = Node()
b = Node()
#删除对象
del a
del b

#获取所有对象
all_objects = gc.get_objects()
for obj in all_objects:
    if isinstance(obj, Node):
        print(f"找到Node对象,地址: {id(obj)}")
#以上代码执行无日志打印,说明Node对象已经不存在。

2. 构建循环引用案例

class Node:
    def __init__(self):
        self.next = None
#实例化Node对象
a = Node()
b = Node()
#循环引用
a.next = b
b.next = a
#删除对象
del a
del b

#获取所有对象
all_objects = gc.get_objects()
for obj in all_objects:
    if isinstance(obj, Node):
        print(f"找到Node对象,地址: {id(obj)}")
#以上代码执行有日志打印,说明Node对象还是存在。
找到Node对象,地址: 4452874272
找到Node对象,地址: 4455658736

在这个例子里,a和b对象相互引用,形成了循环引用。通gc.get_objects()获取所有对象,筛选Node类型对象,可发现循环引用的对象。

当我们进行手工回收后,发现循环引用的对象已经不存在了:

class Node:
    def __init__(self):
        self.next = None

a = Node()
b = Node()
a.next = b
b.next = a
del a
del b

# 强制进行垃圾回收,查看是否能回收对象
gc.collect()

all_objects = gc.get_objects()
for obj in all_objects:
    if isinstance(obj, Node):
        print(f"找到Node对象,地址: {id(obj)}")
#程序执行后,已经没有Node对象了。

五、总结

Python的垃圾回收机制是保障程序稳定运行、高效利用内存的重要组成部分。从基础的引用计数到复杂的标记-清除、分代回收,再到相关函数的使用,每一个环节都有其独特的作用。避开常见的 “坑”,合理利用垃圾回收机制,能让你的Python 代码在内存管理上更加得心应手!

相关文章

Python垃圾回收机制详解

Python 的垃圾回收机制结合了引用计数和分代回收,确保内存高效管理并处理循环引用问题。以下是其核心机制的分步解释:1. 引用计数(Reference Counting)原理:O 每个对象维护一个引...

Python垃圾回收:循环引用检测算法实现

Python内存管理的核心是自动垃圾回收机制,它使开发者能够专注于业务逻辑而无需手动管理内存。Python采用引用计数作为基础内存管理方式,每个对象都有一个引用计数器记录指向它的引用数量。当计数为零时...

使用Python实现垃圾分类系统

1 问题如何使用python实现垃圾分类,这里需要创建多个系统。2 方法在python中实现垃圾分类,需要创建多个系统,整体设计思路垃圾分类学习器包含了学习模块和测试模块两部分,用户可以根据需求对垃圾...

Python常见面试题及解答总结

以下是 Python 常见的面试题及简要答案示例,覆盖基础语法、数据结构、算法和高级特性等方向:一、Python 基础Python 中可变(Mutable)和不可变(Immutable)数据类型有哪些...

新手学Python避坑,学习效率狂飙! 十八、Python 内存管理

Python 的内存管理系统是一个复杂但高效的机制,以下是对其的一些分享。内存管理机制对象的创建与分配:Python 中一切皆对象,当创建一个对象时,例如x = 5,解释器会在内存中为整数对象5分配空...