Python - 内存管理



在 Python 中,**内存管理**是自动的,它涉及处理一个私有堆,其中包含所有 Python 对象和数据结构。Python 内存管理器在内部确保高效地分配和释放此内存。本教程将探讨 Python 的内存管理机制,包括垃圾收集、引用计数以及变量如何在栈和堆中存储。

内存管理组件

Python 的内存管理组件在 Python 程序执行期间提供高效且有效的内存资源利用。Python 有三个内存管理组件:

  • 私有堆 (Private Heap):充当所有 Python 对象和数据的存储主区域。它由 Python 内存管理器内部管理。
  • 原始内存分配器 (Raw Memory Allocator):这个低级组件直接与操作系统交互,以在 Python 的私有堆中保留内存空间。它确保 Python 的数据结构和对象有足够的存储空间。
  • 对象专用分配器 (Object-Specific Allocators):在原始内存分配器之上,一些对象专用分配器管理不同类型对象的内存,例如整数、字符串、元组和字典。

Python 中的内存分配

Python 主要通过两种方式管理内存分配:栈和堆。

栈 - 静态内存分配

在静态内存分配中,内存是在编译时分配的,并存储在栈中。这通常用于函数调用栈和变量引用。栈是一个用于存储局部变量和函数调用信息的内存区域。它基于后进先出 (LIFO) 原则工作,其中最近添加的项目是最先被移除的。

栈通常用于存储基本数据类型的变量,例如数字、布尔值和字符。这些变量具有固定的内存大小,在编译时已知。

示例

让我们来看一个示例,来说明基本类型变量是如何存储在栈中的。在上面的示例中,名为 x、y 和 z 的变量是名为 example_function() 函数中的局部变量。它们存储在栈中,当函数执行完成时,它们会自动从栈中移除。

def my_function():
   x = 5
   y = True
   z = 'Hello'
   return x, y, z

print(my_function())
print(x, y, z)

执行上述程序后,您将获得以下输出

(5, True, 'Hello')
Traceback (most recent call last):
  File "/home/cg/root/71937/main.py", line 8, in <module>
    print(x, y, z)
NameError: name 'x' is not defined

堆 - 动态内存分配

动态内存分配在运行时为非基本类型的对象和数据结构分配内存。这些对象的实际数据存储在堆中,而对它们的引用存储在栈中。

示例

让我们观察一个创建列表的示例,它动态地在堆中分配内存。

a = [0]*10
print(a)

输出

执行上述程序后,您将获得以下结果:

[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

Python 中的垃圾收集

Python 中的垃圾收集是自动释放不再被对象使用的内存的过程,使其可用于其他对象。Python 的垃圾收集器在程序执行期间运行,并在对象的引用计数降至零时激活。

引用计数

Python 的主要垃圾收集机制是引用计数。Python 中的每个对象都维护一个引用计数,该计数跟踪指向它的别名(或引用)的数量。当对象的引用计数降至零时,垃圾收集器将释放该对象。

引用计数的工作原理如下:

  • 引用计数增加− 当创建对对象的新的引用时,引用计数会增加。
  • 引用计数减少− 当对对象的引用被移除或超出作用域时,引用计数会减少。

示例

这是一个演示 Python 中引用计数工作的示例。

import sys

# Create a string object
name = "Tutorialspoint"
print("Initial reference count:", sys.getrefcount(name))  

# Assign the same string to another variable
other_name = "Tutorialspoint"
print("Reference count after assignment:", sys.getrefcount(name)) 

# Concatenate the string with another string
string_sum = name + ' Python'
print("Reference count after concatenation:", sys.getrefcount(name)) 

# Put the name inside a list multiple times
list_of_names = [name, name, name]
print("Reference count after creating a list with 'name' 3 times:", sys.getrefcount(name)) 

# Deleting one more reference to 'name'
del other_name
print("Reference count after deleting 'other_name':", sys.getrefcount(name))  

# Deleting the list reference
del list_of_names
print("Reference count after deleting the list:", sys.getrefcount(name))  

输出

执行上述程序后,您将获得以下结果:

Initial reference count: 4
Reference count after assignment: 5
Reference count after concatenation: 5
Reference count after creating a list with 'name' 3 times: 8
Reference count after deleting 'other_name': 7
Reference count after deleting the list: 4
广告