天天看點

python 開發 -- 02垃圾回收機制

文章目錄

  • ​​一.什麼是垃圾回收機制​​
  • ​​二.為什麼要有垃圾回收機制​​
  • ​​三.垃圾回收機制的原理​​
  • ​​1.引用計數​​
  • ​​2.棧區 / 堆區​​
  • ​​3.總結​​
  • ​​四.标記清除​​
  • ​​1.循環引用問題(也叫交叉引用)​​
  • ​​3.循環引用導緻的結果​​
  • ​​4.解決方法 : 清除-标記​​
  • ​​五.分代回收​​
  • ​​1.效率問題​​
  • ​​2.解決方法 : 分代回收​​

一.什麼是垃圾回收機制

  • 垃圾回收機制(簡稱GC), 解釋器自帶的一種機制
  • 它是一種動态存儲管理技術,自動釋放不再被程式引用的對象所占用的記憶體空間

二.為什麼要有垃圾回收機制

  • 程式的運作過程中會申請大量的記憶體空間
  • 對于一些無用的空間如果不及時清理的話會導緻記憶體溢出(不夠用),程式就會崩潰
  • 管理記憶體是非常複雜的事情,垃圾回收機制就把程式員從複雜的記憶體管理中解放出啦

三.垃圾回收機制的原理

1.引用計數

引用計數就是變量名與變量值的關聯次數, 以此來跟蹤和回收垃圾

  • 直接引用
🌴通過變量名直接引用
x = 18  #18被引用了一次,計數為1
y = x   #18被引用加1次,計數為2
z = y   #18被引用加1次,計數為3
print(id(x))  #140725488808736
print(id(y))  #140725488808736
print(id(z))  #140725488808736      
  • 間接引用
🌴容器對其的引用都是間接
x = 18                 #18被引用一次,計數為1
li = [1,2,x]           #通過清單引用,計數加1,為2
dic = {'age': x}       #通過字典引用, 計數加1,為3
print(id(x))           #140725486514976
print(id(li[2]))       #140725486514976 清單引用,計數4
print(id(dic['age']))  #140725486514976 字典引用,計數5      

2.棧區 / 堆區

  • 棧區 : 存放的是變量名與變量值的記憶體位址映射關系
  • 堆區 : 存放的是值真正的位置

3.總結

  • 直接引用指的是從棧區出發直接引用到的記憶體位址
  • 間接引用指的是從棧區出發引用到堆區後,再通過進一步引用才能到達的記憶體位址

四.标記清除

1.循環引用問題(也叫交叉引用)

🌴我們先定義清單
l1=[0]  # 清單1被引用一次,清單1的引用計數變為1   
l2=[1]  # 清單2被引用一次,清單2的引用計數變為1   

🌴将清單加入另一個清單
l1.append(l2)  # 把清單2追加到l1中作為第二個元素,清單2的引用計數變為2
l2.append(l1)  # 把清單1追加到l2中作為第二個元素,清單1的引用計數變為2

🌴解除比變量名"l1"和"l2"與值的對應關系
del l1
del l2      

3.循環引用導緻的結果

  • 值不再被任何名字關聯,但是值的引用計數并不會為0
  • 應該被回收但又不能被回收

4.解決方法 : 清除-标記

  • 容器對象的的引用都有可能産生循環引用, 而清除-标記就是為解決這個問題的
  • 當應用程式可用空間被耗盡時, 清除-标記會停止整個程式, 然後先标記, 再清除
🌴标記
但凡是可以從棧區出發,找到對應堆區内容的(直接或間接引用)就标記存活,非存活則清除
具體點:标記的過程其實就是,周遊所有的"GC Roots"對象(棧區中的所有内容或者線程都可以作為"GC Roots"對象)
然後将所有"GC Roots"的對象可以直接或間接通路到的對象标記為存活的對象,其餘的均為非存活對象,應該被清除

🌴清除
周遊堆中的對象,将沒有标記存活的對象都清理掉      

五.分代回收

1.效率問題

  • 基于引用計數的回收機制,每次回收記憶體,都需要把所有對象的引用計數都周遊一遍
  • 這是非常消耗時間的,于是引入了分代回收來提高回收效率
  • 分代回收采用的是用**“空間換時間”**的政策。

2.解決方法 : 分代回收

  • 分代
🌴分代指的是根據變量的存活時間來劃分他們的等級
🌴一個變量經常被引用,等級(權重)就會提高,權重達到設定值就會進入下一個等級
🌴當經過多次掃描都沒有被回收,"GC機制"就會認為該變量是常量
🌴于是對其的掃描頻率會降低      
  • 回收
🌴當計數降低,就容易被回收
🌴分代回收可以起到提升效率的效果,但也存在一定的缺點:
    🐏比如一個變量剛從低等級轉入高等級,它就被解除了綁定關系
    🐏它應該被回收,但高等級掃描頻率低于低等級
    🐏那麼這個已被解除綁定關系的變量無法及時得到清理      
  • 總結
🌴垃圾回收機制是在清理垃圾和釋放記憶體的前提下
🌴允許一些垃圾不被釋放為代價(就是等級權重高點的垃圾不會及時被清理)
🌴以此換取引用計數掃描頻率的降低,進而提升其性能
🌴這是一種以空間換時間的解決方案