走進abaqus gui開發(7)--python打基礎

--------------【正文開始】--------------

前言:

前面把動態類型,垃圾回收都淺顯地帶過了,今天著重談一談python中的垃圾回收機制。江湖上都流傳著一“人生苦短我用python!”的口號,很大程度上歸功于,python創世者們設計了一個相對完善的垃圾回收機制。所以今天就通過一些參考案例來看看python如何處理垃圾。

走進abaqus gui開發(7)--python打基礎的圖1

1 垃圾回收的方法
1.1  引用計數法
每個對象維護一個ob_ref字段,用來記錄該對象當前被引用的次數,每當新的引用指向該對象時,它的引用計數ob_ref加1,每當該對象的引用失效時計數ob_ref減1,一旦對象的引用計數為0,該對象立即被回收,對象占用的內存空間將被釋放

1.2 標記清除(Mark—Sweep)

一種基于追蹤回收(tracing GC)技術實現的垃圾回收算法。它分為兩個階段:第一階段是標記階段,GC會把所有的『活動對象』打上標記,第二階段是把那些沒有標記的對象『非活動對象』進行回收。那么GC又是如何判斷哪些是活動對象哪些是非活動對象的呢?

走進abaqus gui開發(7)--python打基礎的圖2

對象之間通過引用(指針)連在一起,構成一個有向圖,對象構成這個有向圖的節點,而引用關系構成這個有向圖的邊。從根對象(root object)出發,沿著有向邊遍歷對象,可達的(reachable)對象標記為活動對象,不可達的對象就是要被清除的非活動對象。根對象就是全局變量、調用棧、寄存器。mark-sweepg 在上圖中,我們把小黑圈視為全局變量,也就是把它作為root object,從小黑圈出發,對象1可直達,那么它將被標記,對象2、3可間接到達也會被標記,而4和5不可達,那么1、2、3就是活動對象,4和5是非活動對象會被GC回收。

1.3 分代回收
以空間換時間的操作方式,Python 將內存根據對象的存活時間劃分為不同的集合,每個集合稱為一個代,Python將內存分為了3“代”,分別為年輕代(第0代)、中年代(第1代)、老年代(第2代),他們對應的是3個鏈表,它們的垃圾收集頻率與對象的存活時間的增大而減小。
新創建的對象都會分配在年輕代,年輕代鏈表的總數達到上限時,Python垃圾收集機制就會被觸發,把那些可以被回收的對象回收掉,而那些不會回收的對象就會被移到中年代去,依此類推,老年代中的對象是存活時間最久的對象,甚至是存活于整個系統的生命周期內。同時,分代回收是建立在標記清除技術基礎之上。分代回收同樣作為Python的輔助垃圾收集技術處理那些容器對象

2 實例解釋
以引用計數法為例子,在Python內部,實際上,每個對象中都保持了一個計數器,計數器記錄了當前指向該對象的引用次數,也就是該對象被引用的次數。一旦這個計數器被設置為零,這個對象的內存空間就會被自動回收。垃圾回收最直接且可感受的好處就是,可以在腳本中任意使用該對象而不需要考慮釋放內存空間。與C和C++這樣的底層語言相比,省去了大量基礎代碼。這些是理論的東西,下面開始上實例。

a=5b=aprint(a)print(b) #變量a和 b數值相同

該實例中,第一行創建了對象5,并將變量a與之關聯,第二行創建了變量b,變量b也成為對象5的一個引用。實際上,變量a和變量b都引用了相同的對象,都指向了相同的內存空間,這在Python語言中叫作共享引用——多個變量名引用同一對象。簡單來說就是對象5只有一個,但存在兩個變量a,b都指向這個對象。
對上述代碼做如下修改:

a=5b=aa ='five' print(a,b)

第三行代碼創建了一個新的對象'"five',并設置a對這個新的對象進行引用,而b仍然繼續引用之前的對象5。
與其他語言不同,在 Python中,給一個變量賦一個新的值,并不是替換了原始的對象,而是重新創建一個不同的對象,并讓這個變量去引用這個新的對象。實際效果就是,對一個變量賦值,僅僅會影響被賦值的變量。
但是,也有一些特殊的情況,當引用一些可變對象時,在原處對對象進行修改時,就會出現不一樣的情況。例如,在一個列表中對某一個偏移位置進行重新賦值時,會改變這個列表對象,而不是生成一個新的對象。首先看一個容易理解的實例:

a=[1,2,31]b=aprint(a)print(b)a=999print(b)

由程序執行結果可以看出,上述實例中一開始變量a和 b都引用了列表對象[1,2,3],后來當對a重新賦值后,創建了新的對象999,并讓a引用了這個新的對象,整個過程中b并沒有發生變化,這與前面的實例類似,同屬于共享引用的范疇。

a=[1,2,31] #創建列表對象[1,2,3]和變量a.并讓 a引用該對象b=a #創建變量b、并讓b引[用同一列表對象print(a)print(b) #變量a和 b數值相同a[0]='one' #修改變量所引用的對象的一個元素print(a) #變量a數值發生變化print(b) #變量b數值也發生變化


在上述程序中,我們沒有改變a,只是改變了a所引用對象的一個元素,這類修改會覆蓋列表對象中的某些部分,它不僅僅會影響變量a,也會同時影響變量b,因為它們引用的是同一個列表對象。對于這種在原處修改的對象,共享引用時需要加倍小心,不注意的話非常容易出錯。
如果不希望上述情況出現時,需要使用Python的對象復制,而不是創建引用。Python有多種復制列表的方法,現列舉如下。

a=[1,2,3]b=a[:] #復制列表print(b)print(a[0])print(a) #a引用的列表中某一元素變化時,b未改變。


這種情況下,對a的修改不會影響b,因為b引用的是a所引用對象的復制,兩個變量指向了不同的內存區域。需要注意的是,這種分片技術不能用于集合和字典等非序列類型的對象中。
除了上述復制方法之外,還可以使用copy()函數實現,例如:

import copya=11,2.31b=copy.copy(a)print(b)print(a[0])print(a)



這些例子都很短小,但是也相當的有代表性,我也是反復的回味這些知識,每每回味都覺得很妙。
古人言,故不積跬步,無以至千里;不積小流,無以成江海。學習一門技術也是這樣,只有持之以恒,才能不斷精進。  走進abaqus gui開發(7)--python打基礎的圖3 走進abaqus gui開發(7)--python打基礎的圖4 走進abaqus gui開發(7)--python打基礎的圖5

登錄后免費查看全文
立即登錄
App下載
技術鄰APP
工程師必備
  • 項目客服
  • 培訓客服
  • 平臺客服

TOP