Python的垃圾回收机制主要包括引用计数、循环垃圾收集和内存池机制。
一、引用计数
1. Python使用引用计数来追踪对象的引用情况,当对象被引用时,其引用计数加一;当引用被删除时,引用计数减一。
2. 当对象的引用计数为零时,垃圾回收机制会处理该对象。
import sys
# 创建一个新的整数对象并将其赋值给变量x
x = 10
# 此时整数对象10的引用计数为1
# 将x赋值给y,即y也引用了整数对象10
y = x
# 整数对象10的引用计数增加为2
# 将x从容器中删除
del x
# 整数对象10的引用计数减少为1
# 将y重新赋值为另一个值
y = 20
# 整数对象10的引用计数减少为0,对象被销毁
# 获取整数对象20的引用计数
ref_count = sys.getrefcount(20) - 1 # 减去函数参数本身的引用
print(ref_count) # 输出:1
二、循环垃圾收集
1. 当存在循环引用时,即使对象的引用计数不为零,垃圾回收机制也会检测并清理这些循环引用。
创建了两个相互引用的Person对象,并使用del语句删除了对这些对象的引用由于它们相互引用,单纯的引用计数机制无法将它们回收。但是当我们删除了所有外部引用后,垃圾回收机制会检测到这种循环引用(不可访问对象的循环)并正确地回收这些对象。
import gc
# 创建一个循环引用的例子
class Node:
def __init__(self, data):
self.data = data
self.next = None
# 创建两个Node对象,并相互引用
node1 = Node(1)
node2 = Node(2)
node1.next = node2
node2.next = node1
# 显示垃圾回收前的对象数量
before_count = len(gc.get_objects())
# 删除对象的引用
del node1
del node2
#node1和node2对象被干掉了,但是堆内存中有相互引用,引用计数位为1;可是没有变量去接收,这些内存地址程序员想用都不能用到,并且还占用内存
# 手动触发gc.collect()来执行垃圾回收,清除循环引用的对象。
gc.collect()
# 显示垃圾回收后的对象数量
after_count = len(gc.get_objects())
print("Objects before GC:", before_count)
print("Objects after GC:", after_count)
```
常见的垃圾回收有三种: 分别是标记清除、标记整理、和复制这三种算法,下面先从第一种标记清除算法来学习。标记清除算法是一种垃圾回收算法,分为标记阶段和清除阶段。在标记阶段,活动对象会被打上标记,而在清除阶段,没有标记的非活动对象会被回收。判断对象是否是垃圾是通过沿着GC Root对象的引用链进行查找,如果对象没有被GC Root直接或间接引用,则可以被回收。
三、内存池机制
1.Python使用内存池管理对小块内存的申请和释放,以提高执行效率。
2. 小于256个字节的对象使用pymalloc实现的分配器,而大的对象则使用系统的malloc。
3. 对于不同类型的对象(如整数、浮点数和列表),它们有独立的私有内存池,不共享内存池。
import sys
# 分配小于256字节的对象
small_object1 = "Hello"
small_object2 = 123
# 分配大的对象
big_object1 = [1, 2, 3, 4, 5]
big_object2 = ['10', '20', '30', '40', '50']
# 查看对象所使用的内存池
print(sys.getsizeof(small_object1)) # 54
print(sys.getsizeof(small_object2)) # 28
print(sys.getsizeof(big_object1)) # 120
print(sys.getsizeof(big_object2)) # 120