目录
- 内存分配方式
- 自动内存管理
- 内存分配策略
- 垃圾回收机制
- 引用计数垃圾回收
- 对象创建和引用关系
- 引用计数的状态
- 删除变量
- 标记 - 清除垃圾回收
- 内存分配的区域划分
- 栈内存
- 堆内存
- 内存管理的优化
- 内存池技术
- 对象共享
Python 的内存管理机制是其运行效率和安全性的重要保障,主要包括以下几个方面:
内存分配方式
自动内存管理
- Python 采用自动内存管理,主要通过垃圾回收机制来实现。它不需要程序员手动释放内存【典型的例子C和C++,使用malloc和free等函数】,大大减少了内存泄漏等错误的发生。例如,在 Python 中创建一个列表对象:
当这个列表不再被任何变量引用时,Python 的垃圾回收机制会自动回收它所占用的内存。my_list = [1, 2, 3]
- 这种自动管理方式使得程序员可以更专注于程序逻辑的实现,而不是内存管理的细节。
内存分配策略
- Python 使用引用计数作为主要的内存分配策略。每个对象都有一个引用计数器,当一个对象被创建时,它的引用计数器被设置为 1。例如:
此时,整数对象 10 的引用计数为 1。a = 10
- 当一个对象被赋值给另一个变量时,引用计数会增加。例如:
整数对象 10 的引用计数变为 2。b = a
- 当一个对象被删除或者其引用被重新赋值给其他对象时,引用计数会减少。例如:
整数对象 10 的引用计数变为 1。当引用计数变为 0 时,Python 的垃圾回收机制就会回收该对象所占用的内存。del a
垃圾回收机制
引用计数垃圾回收
- 这是 Python 最主要的垃圾回收方式。如前面所述,通过引用计数来判断对象是否还有用。这种方式的优点是简单高效,能够及时回收不再使用的对象。例如,一个复杂的嵌套数据结构,当它的顶层变量被删除后,其内部所有对象的引用计数都会逐渐减少,一旦变为 0 就会被回收。
- 但是引用计数也有缺点,它无法处理循环引用的情况。例如:
a = [] b = [] a.append(b) b.append(a)
- 循环引用是指两个或多个对象之间互相引用,形成一个闭环。这种情况下,即使这些对象没有被外部变量引用【a 中的元素(即 b)和 b 中的元素(即 a)是内部的引用关系,这些引用关系是对象内部的结构,而不是外部变量的直接引用】,它们的引用计数也不会为0,因为它们互相引用。
对象创建和引用关系
a = []
创建了一个空列表对象a
,此时a
的引用计数为 1(a
本身引用了它)。b = []
创建了另一个空列表对象b
,此时b
的引用计数也为 1(b
本身引用了它)。a.append(b)
将对象b
添加到列表a
中,此时b
的引用计数增加 1,变为 2(b
本身和a
中的元素引用了它)。b.append(a)
将对象a
添加到列表b
中,此时a
的引用计数也增加 1,变为 2(a
本身和b
中的元素引用了它)。
引用计数的状态
现在,a
和 b
的引用计数都是 2:
a
被a
本身和b
中的元素引用。b
被b
本身和a
中的元素引用。
删除变量
假设我们执行以下操作:
del a
del b
- 删除变量
a
后,a
的引用计数减少 1,变为 1(只剩下b
中的元素引用它)。 - 删除变量
b
后,b
的引用计数也减少 1,变为 1(只剩下a
中的元素引用它)。
此时,a
和 b
的引用计数仍然为 1,因为它们互相引用。即使我们删除了外部变量 a
和 b
,它们的引用计数也不会变为 0,因此引用计数机制无法回收它们。
标记 - 清除垃圾回收
- 为了处理循环引用的问题,Python 还采用了标记 - 清除垃圾回收机制。该机制会定期运行,它从根对象集合(如全局变量、栈中的变量等)开始,标记所有可达的对象。然后扫描整个内存堆,将未标记的对象视为垃圾进行回收。
- 例如,在上述循环引用的例子中,当标记 - 清除机制运行时,它会发现 a 和 b 之间虽然互相引用,但它们没有被根对象【在 Python 的垃圾回收机制中,根对象是指那些始终被程序直接引用的对象;例如:全局变量、局部变量、活动对象、内置对象等】集合引用,所以会被标记为垃圾并回收。
内存分配的区域划分
栈内存
- 主要用于存储局部变量、函数调用的上下文等。在 Python 中,当一个函数被调用时,会为其创建一个栈帧,栈帧中包含了函数的局部变量等信息。例如:
当调用def my_function():x = 10y = 20return x + y
my_function()
时,会创建一个栈帧,其中存储了变量 x 和 y。栈内存的分配和释放速度很快,当函数调用结束时,栈帧会被销毁,其中的变量占用的内存也会被释放。
堆内存
- 主要用于存储对象实例等。例如,创建一个类的实例:
这里的class MyClass:def __init__(self, value):self.value = value obj = MyClass(100)
obj
是一个对象实例,它存储在堆内存中。堆内存的分配和释放相对复杂,需要通过垃圾回收机制来管理。
内存管理的优化
内存池技术
- Python 的内存管理使用了内存池技术。内存池是一种预先分配一块较大的内存空间,然后从这个空间中分配小块内存给对象的技术。例如,对于小整数(通常在 -5 到 256 之间),Python 会预先分配好这些整数对象存储在内存池中,当程序需要使用这些小整数时,直接从内存池中获取,避免了频繁的内存分配和释放操作,提高了内存分配的效率。
对象共享
- Python 会尽量共享一些不可变对象。例如,字符串对象在某些情况下会共享。如果程序中有多个地方使用相同的字符串,Python 会尽量让它们指向同一个字符串对象,而不是创建多个相同的字符串对象,这样可以节省内存空间。