1. 程式人生 > >Python 垃圾回收

Python 垃圾回收

進入 不足 gpo 由於 常用 異常 觸發 collect 我們

Python 的內存管理是自動的。Python 使用引用計數和垃圾回收來管理內存。

引用計數:每個對象有一個引用它的對象數目。引用計數為 0 的對象被視作垃圾。當一個引用它的對象創建時,引用計數加一,當一個引用它的對象銷毀時,引用計數減一。

引用計數有一些缺點,其中一個是它不能處理循環引用。

def make_cycle():
    1 = [ ]
    1.append(l)

make_cycle()

因為 make_cycle() 中創建了一個循環引用對象,所以當函數返回後,它並不會被引用計數回收。

自動回收引用對象

因為循環引用需要消耗計算資源來發現,所以垃圾回收是一個預先安排好的任務。Python 基於分配對象與回收對象的差值來安排垃圾回收。當分配數目減去回收數目大於臨界值時,觸發垃圾回收。可以通過 gc 模塊來查看垃圾回收的臨界值:

import gc
gc.get_threshold()
(700, 10, 10)

我們可以看到,默認的臨界值時 700。

當你的 Python 程序耗盡了內存後,自動垃圾回收不會運行。你的程序會拋出異常,這個異常必須被處理,否則你的程序會崩潰。這是由於自動垃圾回收是基於對象的數目而不是基於對象的大小。因此可以考慮在占據大量內存的代碼後手動運行垃圾回收。

手動垃圾回收

對於一些程序,尤其是長時間運行的服務端程序或者嵌入式程序,自動垃圾回收可能不足。

手動執行垃圾回收:

import gc
# 返回它回收的對象數目
gc.collect()

如果我們創建一些循環引用,我們可以看到手動回收生效了:

# -*- coding: utf-8 -*-
import gc def _make_cycle(): l = {} l[0] = l def make_cycle(num=1): for i in range(num): _make_cycle() # 先清理幹凈 gc.collect() assert gc.collect() == 0 make_cycle(10) assert gc.collect() == 10

通常,有兩種手動回收的策略:

  • 基於時間。定時調用垃圾回收。
  • 基於事件。在一個事件中調用垃圾回收。比如當一個用戶與服務器斷開連接或者知道應用要進入停頓狀態後。

推薦行為

盡可能在需要的時候調用垃圾回收來避免對重要程序造成性能影響。垃圾回收應該是設計 Python 應用的一部分。

  • 不要隨意運行垃圾回收,因為它需要消耗很多計算資源來計算每個內存對象
  • 在你的應用完全啟動並進入平穩運行狀態後再運行垃圾回收。這可能可以釋放大量用於打開、解析文件、編輯、修改對象後者不會再用到的模塊的內存
  • 在運行不常用代碼後運行垃圾回收。比如,在一個一天一次的解析、導出數據的任務後運行垃圾回收
  • 在對時間要求高的任務前後運行垃圾回收來阻止可能的垃圾回收分走運行時間

參考

  1. https://www.digi.com/resources/documentation/digidocs/90001537/references/r_python_garbage_coll.htm

Python 垃圾回收