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
廣告