日常 Python:我們到底需不需要手動刪除不用的變數
這幾天透過龍哥寫的為你自己學 Python 複習 Python,讀到「刪除變數」的章節時,文章開頭是這麼說:
變數宣告之後,如果不需要的話應該怎麼處理?因為「宣告」這個行為表示你要請電腦分一小塊記憶體給你存放這個變數,本著「有借有還再借不難」的好習慣,照理說如果確定之後不會再用到的話,應該要把佔用的記憶體還給系統。
讀到這邊,還先不要斷章取義,擅自決定從今天起,我要養成手動刪除變數的好習慣!我們先繼續看下去:
有些程式語言是需要手動做這件事的,但在 Python 不用我們操心,Python 有自己的資源回收機制(Garbage Collection)會幫我們搞定這些事情。
抓到重點了嗎?Python 有「資源回收機制(Garbage Collection)」。
所以乍看之下,我們似乎不用太擔心變數慢慢蠶食記憶體,不過既然如此,為什麽 Python 還需要提供 del
這個關鍵字(keyword)讓我們可以自行刪除變數呢?
是誰佔用了記憶體?
在開始解說資源回收機制(Garbage Collection)與 del
之前,我們需要先釐清一件事——「到底是變數佔用了記憶體,還是變數的值佔用了記憶體?」
實際上,佔用記憶體是變數的值,我們可以想像變數的值是一隻小貓,無論小貓叫「咪咪、小白、阿虎、肥肥」,小貓是真實存在的實體(重量可能還很重),而小貓的名字(也就是變數)只是一個參考名稱(reference),用來指向存儲於記憶體的物件,也是這隻小貓(變數的值)。
(這是一隻叫柴犬的貓,這樣他是貓還是狗?)
所以小結一下:
- 變數:一個標籤或名稱,用於引用記憶體中的物件。
- 值(物件):實際存儲在記憶體中的數據內容,會佔用其空間。
del
實際的作用是什麼?
在為你自己學 Python 的〈刪除變數〉章節中有提到——如果你宣告了變數但因為某些原因現在就不想用了,你可以使用 Python 內建的 del
關鍵字來把變數刪掉:
柴犬 = "cat"
print(柴犬) # 印出 "cat"
del 柴犬
print(柴犬) # NameError: name '柴犬' is not defined.
因為刪除了 柴犬
變數,所以 柴犬
變數就變成沒有定義,如果要使用它就會出現 NameError
的錯誤訊息。
然而 del
實際上的功用,並不是將變數 柴犬
的值(也就是字串 "cat"
)刪除,而是將變數 柴犬
與字串 "cat"
的參考連結(reference)斷開,然後再變數名稱 柴犬
刪掉。
(斷開連結!)
換成生活化的例子,可以理解為貓("cat"
)還在,但這隻貓已經不叫柴犬
了,所以你如果嘗試使用柴犬
,也不會有貓回應你。
啊,沒有名字的貓怎麼辦?
資源回收機制登場了
接續剛剛的例子,我們可以把「沒有名字的貓」當作是流浪貓,當這隻貓一直處於流浪狀態,沒有人願意給他一個名字(變數名稱),藉此與貓產生連結的話,資源回收機制(Garbage Collection)會像動管大隊,把這隻貓帶走,從此牠就從記憶體中消失了。(怎麼有種淡淡的哀傷 ⋯⋯)
但這邊有件事沒說清楚的是——「什麼時候才會觸發資源回收機制呢?」
在 Python 中,有一種名為「參照計數(Referencing Counting)」的記憶體管理技術,它會用來追蹤物件被引用(reference)的次數,當物件的參照計數變成 0 時,Python 的垃圾回收機制會自動釋放該物件佔用的記憶體。
那什麼時候參照計數會變成 0 呢?
所有變數的引用被刪除或重新分配
當變數不再指向物件時,物件的引用計數會減少。如果沒有其他引用,計數變為 0。
a = [1, 2, 3] # 創建列表,引用計數為 1
b = a # 引用計數為 2
del a # 刪除變數 a,引用計數為 1
del b # 刪除變數 b,引用計數為 0,物件被回收
物件離開作用域
局部變數在函數執行結束後自動被釋放,引用計數變為 0。
def create_list():
temp_list = [1, 2, 3] # temp_list 的引用計數為 1
return temp_list
result = create_list() # temp_list 離開作用域後被回收,但 result 引用該物件
如果 result
沒有指向返回的物件(也就是 create_list()
),則物件的引用計數會變為 0。
變數被重新分配
當變數指向新物件時,原本指向的物件的引用計數會減少。
a = [1, 2, 3] # 創建列表,引用計數為 1
a = [4, 5, 6] # 原物件的引用計數變為 0,內存被回收
手動使用 del
刪除變數
del
語句可以刪除對物件的引用,導致引用計數減少。
a = [1, 2, 3] # 引用計數為 1
del a # 引用計數變為 0,物件被回收
小結
如果要無腦地說,確實在 Python 中,我們不需要為了節省記憶體空間太過操心,資源回收機制(Garbage Collection)像是一個貼心的媽媽,看到我們不需要使用的時候,會自動幫我們收整沒在使用的物件。
不過媽媽的存在是有代價的,其中一個顯而易見的壞處是會造成性能下降,因為資源回收機制會需要定期掃描記憶體檢測無用無間,這也會進提升 CPU 額外的負擔。
如果想要更進一步瞭解 Python 記憶體資源回收機制,那就要繼續底層深掘 Python 文件跟原始程式碼了。
參考資料
如果本文章對你有幫助,歡迎按讚或者留言討論 ヽ(●´∀`●)ノ
本文同步發佈於作者的 Medium 網站