Python基础(①④内存管理机制)
Python 的内存管理机制可以简单理解为 “自动帮你管钱”—— 你不用手动申请或释放内存,Python 会自动处理。
1. 引用计数
a = [1,2,3] # 列表[1,2,3]的引用计数=1
b = a # 引用计数=2(a和b都指向它)
del a # 引用计数=1(只剩b了)
b = 100 # 引用计数=0(没人指向列表了),内存被自动回收
当一个对象的引用计数降为0时,Python 的垃圾回收机制会认为这个对象不再被任何变量使用,然后自动回收其占用的内存。
当引用计数变为 0 时,Python 的垃圾回收器就会识别出这个列表是“垃圾”(即无用的内存),并自动释放它占用的内存。从那一刻起,列表 [1,2,3]
的内容就从内存中消失了。
2. 垃圾回收
# 创建两个空列表,互相引用
a = []
b = []
a.append(b) # a引用b
b.append(a) # b引用a# 现在删除a和b的引用
del a
del b
这时候,两个列表已经没有变量指向它们了,但因为它们互相引用(a 里有 b,b 里有 a),导致引用计数都不为 0。
如果只靠引用计数,这两个列表会一直占着内存,变成 “内存垃圾”。
把 a = [] 想象成:有一个空盒子 A,上面贴了个标签 a(方便你找到它)。
把 b = [] 想象成:有一个空盒子 B,上面贴了个标签 b。
现在执行 a.append(b):
相当于往盒子 A 里放了一张纸条,纸条上写着 “盒子 B 在哪”(也就是记录了 B 的位置)。
这时候,盒子 B 除了自己的标签 b,又多了一个被盒子 A “记住” 的引用,所以引用计数 + 1。
再执行 b.append(a):
相当于往盒子 B 里也放了一张纸条,写着 “盒子 A 在哪”。
同理,盒子 A 的引用计数也 + 1(除了标签 a,又被盒子 B 记住了)。
现在,如果你把标签 a 和 b 撕掉(del a; del b):
盒子 A 和 B 虽然没了外部标签,但盒子 A 里的纸条还指着 B,盒子 B 里的纸条还指着 A。
就像两个盒子互相用绳子拴着,虽然没人拿着它们了,但它们自己还互相牵着,所以 “引用计数”(被多少东西指着)都没降到 0。
这就是 “[] 指向 []” 的本质:列表(盒子)里存了另一个列表(盒子)的位置,形成了互相 “惦记” 的关系,导致即使外部没人用了,它们的引用计数也不为 0。
3. 内存池
import sys# 查看两个小整数的内存地址
a = 10
b = 10
print("小整数的内存地址:")
print(id(a)) # 输出a的内存地址
print(id(b)) # 输出b的内存地址
print("两个地址是否相同?", id(a) == id(b)) # 结果为True# 查看两个大整数的内存地址
c = 1000000
d = 1000000
print("\n大整数的内存地址:")
print(id(c)) # 输出c的内存地址
print(id(d)) # 输出d的内存地址
print("两个地址是否相同?", id(c) == id(d)) # 结果为False
小整数10的两个变量a和b指向同一个内存地址(内存池里的缓存)
大整数1000000的两个变量c和d指向不同的内存地址(没有使用内存池)
这就是内存池的效果:
Python 会提前在内存池里缓存一些常用的小数据(比如 - 5 到 256 之间的整数、短字符串)
当你再次创建相同的小数据时,直接复用内存池里的地址,不用重新申请内存
大数据不放进内存池,每次创建都会新申请内存
这样做的好处是:小数据使用频繁,复用内存能节省时间和空间,让程序跑得更快。