赋值仅增加原对象引用计数,不创建新对象;浅拷贝创建新容器对象并参与引用计数,其内部仍共享子对象,形成独立引用链,影响垃圾回收时机。

赋值操作和浅拷贝在垃圾回收的引用计数机制中,**表面看都增加了对原对象的引用,但关键区别在于:赋值不产生新对象,而浅拷贝创建了新容器对象——这个新对象自身也参与引用计数,且拥有独立的引用关系链。**
赋值:仅增加一个引用,不创建新对象
赋值(=)只是把变量名绑定到已有对象上,不分配新内存,也不生成新对象。
- 原对象的引用计数 +1,仅此而已;
- 没有新对象诞生,因此不会新增任何需要被 GC 管理的实体;
- 两个变量(如
a和b)指向同一对象,id(a) == id(b)为真; - 一旦所有变量解绑(比如
a = None、b = None),该对象引用计数归零,立即被回收。
浅拷贝:创建新容器对象,但内部仍共享子对象
浅拷贝(如 copy.copy()、list[:]、dict.copy())会分配一块新内存,生成一个**全新的顶层容器对象**。
- 这个新容器对象本身有自己的引用计数(初始为 1),它是一个独立的 GC 可见对象;
- 容器内若含可变子对象(如嵌套列表、字典),这些子对象的引用计数也会 +1(因为新容器持有了它们的引用);
- 但子对象本身未被复制,所以
id(a[0]) == id(b[0])对嵌套可变项依然成立; - 只有当顶层容器对象和所有持有它的变量都被销毁,且其内部引用的子对象也失去全部外部引用时,子对象才会被回收。
为什么这个区别影响垃圾回收行为?
因为 Python 的引用计数是**按对象粒度**统计的,不是按变量或层级统计的。
- 赋值产生的多个变量,共用同一个对象的计数器;
- 浅拷贝则引入了额外的对象节点:新容器 → 子对象,形成一条新的引用路径;
- 这意味着即使原始对象被解除所有绑定,只要浅拷贝出的容器还活着,它所引用的那些子对象就仍被“拖住”,无法被回收;
- 尤其在循环引用场景中,浅拷贝可能无意中延长子对象生命周期,加剧内存滞留风险。
一个小例子说明引用计数变化
假设:
a = [[1, 2], 'hello'] b = a # 赋值:a 和 b 共享同一 list 对象 c = copy.copy(a) # 浅拷贝:c 是新 list,但 c[0] 仍指向原 [1,2]
-
[[1,2], 'hello']的引用计数 = 2(被a和c引用); -
[1,2]的引用计数 = 2(被a[0]和c[0]引用); - 执行
del a后,顶层列表引用计数减为 1(c还持有着),[1,2]计数不变; - 只有
del c后,两个对象才可能同时被回收(若无其他引用)。










