You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python垃圾回收器如何追踪引用?及id()内置函数行为疑问

嘿,这两个问题都是Python入门时很容易困惑的点,我来帮你理清楚:

1. Python中的垃圾回收器如何追踪引用?

Python的垃圾回收主要靠引用计数作为核心机制,再配合其他辅助机制解决短板,具体追踪逻辑是这样的:

  • 引用计数的基础追踪:每个Python对象的底层结构体里都维护着一个ob_refcnt(引用计数器)。当你做这些操作时,计数器会自动变化:

    • 把对象赋值给变量、作为参数传给函数、添加到列表/字典等容器中 → 计数器+1
    • 变量超出作用域、被重新赋值、用del删除引用,或者容器中的对象被移除 → 计数器-1
      当计数器降到0时,这个对象会被立即销毁,释放占用的内存。
  • 解决循环引用的补充机制:引用计数搞不定循环引用(比如两个对象互相引用,A引用B,B引用A,它们的计数器永远不会到0)。所以Python还搭配了:

    • 标记-清除算法:定期扫描所有对象,标记出所有能被全局变量、栈帧等“根对象”访问到的可达对象,然后清除所有不可达的对象(包括循环引用的对象)。
    • 分代回收:根据对象的存活时间把它们分成3代(年轻代、中年代、老年代),对存活越久的对象,扫描频率越低——因为存活久的对象更可能是长期需要的,这样能减少垃圾回收的性能开销。
2. 关于id()函数在数字、字符串上的行为困惑

你的示例完全符合Python的运行逻辑,咱们一步步拆解为什么会出现这样的结果:

首先看初始代码:

x = 100
y = x  # x和y指向同一个值为100的对象
id(x)  # 输出162569156
id(y)  # 输出162569156

这一步很直观:x和y都引用了同一个整数对象,所以id()返回的内存地址完全相同——id()的作用就是返回对象在内存中的唯一标识。

然后你修改x的指向:

x = 200  # 此时x指向新对象,原对象的引用计数应减少
id(y)  # 仍为162569156
id(x)  # 变为162569932

这里的关键是Python的小对象缓存优化:

  • 对于整数,Python默认会缓存[-5, 256]范围内的所有整数对象。这些对象会被提前创建好,重复使用,而不是每次赋值都新建对象。所以你x = 100时,其实是直接引用了缓存池里的100对象;当x被重新赋值为200时,y仍然引用着缓存池里的100对象,它的引用计数从2降到了1(因为x不再引用它了),但计数没到0,所以对象不会被回收,id(y)自然保持不变。
  • 对于字符串,Python也有**字符串驻留(interning)**机制:短字符串、或者符合标识符规则(比如只包含字母、数字、下划线)的字符串会被缓存,所以不同变量的相同字符串也可能共享同一个对象,返回相同的id()。

你提到的引用计数机制在这里是完全生效的:原100对象的引用计数确实减少了1,但因为还有y在引用它,所以不会被垃圾回收。如果此时你执行del y,这个100对象的引用计数会降到0——不过因为它在缓存池里,Python通常不会真的销毁它,而是继续保留在缓存中,供后续代码复用。


内容的提问来源于stack exchange,提问作者Achal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:57:12