- Python内存管理与对象生命周期
- 内存地址管理:
- 当定义
MyClass
类时,Python解释器会在内存中为该类对象分配一块区域,存储类的定义信息,包括属性和方法的定义等。
- 当创建
obj1 = MyClass()
时,Python在堆内存中为MyClass
的实例对象分配空间,这块空间存储实例的属性值(如果有)。obj1
变量在栈内存中存储,它指向堆内存中MyClass
实例对象的地址。同样,当创建obj2 = MyClass()
时,又在堆内存中为新的MyClass
实例对象分配空间,obj2
变量在栈内存中指向这个新的地址。
- 当执行
obj1 = obj2
时,obj1
变量原来指向的堆内存地址的引用计数减1(如果引用计数变为0,该对象所占用的内存空间会被垃圾回收机制回收),obj1
变量开始指向obj2
所指向的堆内存地址,此时obj2
所指向对象的引用计数加1。
- 对象生命周期:
- 一个
MyClass
实例对象的生命周期从创建开始,即使用MyClass()
创建实例时。只要有变量引用这个对象(即对象的引用计数大于0),它就会一直存在于内存中。
- 当一个对象的引用计数降为0时,Python的垃圾回收机制会将其标记为可回收对象,在合适的时机回收该对象所占用的内存空间。例如,
obj1
原来指向的对象,在obj1 = obj2
后,如果没有其他变量引用它,它的引用计数降为0,就可能被垃圾回收。
- 利用
sys.getrefcount
观察变化
import sys
class MyClass:
pass
obj1 = MyClass()
obj2 = MyClass()
# 获取obj1的初始引用计数
ref_count_obj1 = sys.getrefcount(obj1)
print(f"obj1初始引用计数: {ref_count_obj1}")
# 获取obj2的初始引用计数
ref_count_obj2 = sys.getrefcount(obj2)
print(f"obj2初始引用计数: {ref_count_obj2}")
obj1 = obj2
# 获取obj1指向obj2后的引用计数
new_ref_count_obj1 = sys.getrefcount(obj1)
print(f"obj1指向obj2后引用计数: {new_ref_count_obj1}")
# 这里可以想象之前obj1指向的对象,如果没有其他引用,已被垃圾回收,无法再获取其引用计数
- 在上述代码中,
sys.getrefcount
函数可以获取对象的引用计数。每次获取引用计数时,由于函数调用本身会创建一个临时引用,所以实际看到的引用计数会比正常情况多1。通过观察obj1
和obj2
在不同操作前后的引用计数变化,可以直观地看到Python内存管理中对象引用计数的变化情况,从而了解对象的生命周期和内存地址管理。