目錄
- 內存分配方式
- 自動內存管理
- 內存分配策略
- 垃圾回收機制
- 引用計數垃圾回收
- 對象創建和引用關系
- 引用計數的狀態
- 刪除變量
- 標記 - 清除垃圾回收
- 內存分配的區域劃分
- 棧內存
- 堆內存
- 內存管理的優化
- 內存池技術
- 對象共享
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 會盡量讓它們指向同一個字符串對象,而不是創建多個相同的字符串對象,這樣可以節省內存空間。