
*****
## Python 垃圾回收機制
計數引用我們反復提過好幾次, Python 中一切皆對象。因此,你所看到的一切變量,本質上都是對象的一個指針。
<br>那么,怎么知道一個對象,是否永遠都不能被調用了呢?
<br>就是當這個對象的引用計數(指針數)為 0 的時候,說明這個對象永不可達,自然它也就成為了垃圾,需要被回收。
~~~
import os
import psutil
# 顯示當前 python 程序占用的內存大小
def show_memory_info(hint):
pid = os.getpid()
p = psutil.Process(pid)
info = p.memory_full_info()
memory = info.uss / 1024. / 1024
print('{} memory used: {} MB'.format(hint, memory))
def func():
show_memory_info('initial')
a = [i for i in range(10000000)]
show_memory_info('after a created')
func()
show_memory_info('finished')
~~~
### 循環引用
如果有兩個對象,它們互相引用,并且不再被別的對象所引用,那么它們應該被垃圾回收嗎?
~~~
def func():
show_memory_info('initial')
a = [i for i in range(10000000)]
b = [i for i in range(10000000)]
show_memory_info('after a, b created')
a.append(b)
b.append(a)
func()
show_memory_info('finished')
~~~
### 調試內存泄漏
雖然有了自動回收機制,但這也不是萬能的,難免還是會有漏網之魚。內存泄漏是我們不想見到的,而且還會嚴重影響性能。有沒有什么好的調試手段呢?
它就是 objgraph,一個非常好用的可視化引用關系的包。在這個包中,我主要推薦兩個函數,第一個是 show\_refs(),它可以生成清晰的引用關系圖。
~~~
import objgraph
a = [1, 2, 3]
b = [4, 5, 6]
a.append(b)
b.append(a)
objgraph.show_refs([a])
~~~

dot轉圖片:[https://onlineconvertfree.com/zh/](https://onlineconvertfree.com/zh/)
### 總結
* 垃圾回收是 Python 自帶的機制,用于自動釋放不會再用到的內存空間;
* 引用計數是其中最簡單的實現,不過切記,這只是充分非必要條件,因為循環引用需要通過不可達判定,來確定是否可以回收;
* Python 的自動回收算法包括標記清除和分代收集,主要針對的是循環引用的垃圾收集;
* 調試內存泄漏方面, objgraph 是很好的可視化分析工具。