① 舉例說明一個典型的垃圾回收演算法
關於java里的垃圾回收演算法,初學者經常產生的疑問是,像這樣的代碼里的無用單元:
class Test{
public Test test = null;
public static void main(String args[]){
Test t1 = new Test();
Test t2 = new Test();
t1.test=t2;
t2.test=t1;
t1=null;
t2=null;
}
}
java能不能自動回收?
java是可以回收的.對此有疑問的人的想法是以為java是採用引用計數法實現垃圾回收的.實際上,java不是用此方法,所以可以回收.
1:引用計數,如下,當單元count=0時回收此單元
Test t1 = new Test();//t1指向單元count=1
Test t2 = new Test();//t2指向單元count=1
t1.test=t2;//t2指向單元count++,count=2
t2.test=t1;//t2指向單元count++,count=2
t1=null;//t1指向單元count--,count=1
t2=null;//t2指向單元count--,count=1
兩單元均不可達,為無用單元,但引用計數count=1,!=0,不能回收.
2:java的演算法(簡化)
基本思想:為了避免懸掛引用,寧可產生無用單元,只在空間用完,需要新單元時才進行垃圾回收.
過程:
1:標記Mark
首先,所有單元標記為off,然後,java所有thread的棧stack內引用的單元標記為on,對所有標記為on的單元引用的其他單元標記為on.
2:掃描Sweep
掃描堆heap,所有標記為off的單元一概回收.
所以,上述程序中無用單元是可以回收的.
② JVM有哪些垃圾回收演算法
標記-清除,標記-復制,標記-整理
③ 現在android上的Dalvik是用哪個垃圾回收演算法
Dalvik虛擬機使用Mark-Sweep演算法來進行垃圾收集。顧名思義,Mark-Sweep演算法就是為Mark和Sweep兩個階段進行垃圾回收。其中,Mark階段從根集(Root Set)開始,遞歸地標記出當前所有被引用的對象,而Sweep階段負責回收那些沒有被引用的對象。
④ 「sweep」的過去時和過去分詞怎麼寫
「sweep」的過去時是swept,過去分詞也是swept。
sweep
英 [swiːp] 美 [swip]
vt. 掃除;猛拉;撣去
vi. 掃,打掃;席捲;掃視;襲擊
n. 打掃,掃除;范圍;全勝
短語
1、sweep off拂去 ; 大量清除 ; 掃去 ; 掃清
2、sweep rate掃描速度 ;[雷達]掃描速率 ;[電子]掃描頻率 ; 掃描率
3、sweep templete造模刮板 ; 制模刮板
4、Temperature Sweep溫度掃描分析 ; 溫度掃描 ; 溫度分析 ; 溫度掃描分析參數設置
5、Sweep Time[電子][計]掃描時間 ; 掃頻速率 ; 掃描 ; 掃描時間英語
6、Sweep speed[電子]掃描速度 ; 掃描速度英語
7、sweep generator[電子]掃描發生器 ; 掃描振盪器 ; 掃頻信號發生器 ; 掃描頻率發生器
8、Sweep Oar單槳 ; 大槳
9、Sweep Algorithm掃描演算法 ; 掃描法 ; 掃描線演算法
(4)sweep演算法擴展閱讀
雙語例句
1、I can't sweep without a broom.
沒有掃帚我無法掃。
2、Sweep the room out well.
把這房間好好打掃一下。
3、Sprinkle some water before you sweep.
先潑點兒水再掃。
4、There are some proposals for removing the rubbish, like creating a series of lasers that would sweep the trash back into our atmosphere, where it would mostly burn up.
有一些關於清除太空垃圾的提議,如創造了一系列的激光將垃圾掃回我們的大氣層,垃圾在大氣層里差不多都能燃燒殆盡。
5、Save Our Secret Ballot amendments prevent adoption of card-check laws by other states—but the NLRB』s lawsuits could sweep those protections aside as well.
《拯救我們的無記名投票》修正案會阻止其他州採用卡片檢查法律——但NLRB的訴訟可能將這些保護也一並掃除。
⑤ JAVA垃圾收集的演算法是怎麼樣的
Java語言規范沒有明確地說明JVM使用哪種垃圾回收演算法,但是任何一種垃圾收集演算法一般要做2件基本的事情:(1)發現無用信息對象;(2)回收被無用對象佔用的內存空間,使該空間可被程序再次使用。 (課課家教育)
大多數垃圾回收演算法使用了根集(root set)這個概念;所謂根集就量正在執行的Java程序可以訪問的引用變數的集合(包括局部變數、參數、類變數),程序可以使用引用變數訪問對象的屬性和調用對象的方法。垃圾收集首選需要確定從根開始哪些是可達的和哪些是不可達的,從根集可達的對象都是活動對象,它們不能作為垃圾被回收,這也包括從根集間接可達的對象。而根集通過任意路徑不可達的對象符合垃圾收集的條件,應該被回收。下面介紹幾個常用的演算法。
1、 引用計數法(Reference Counting Collector)
引用計數法是唯一沒有使用根集的垃圾回收的法,該演算法使用引用計數器來區分存活對象和不再使用的對象。一般來說,堆中的每個對象對應一個引用計數器。當每一次創建一個對象並賦給一個變數時,引用計數器置為1。當對象被賦給任意變數時,引用計數器每次加1當對象出了作用域後(該對象丟棄不再使用),引用計數器減1,一旦引用計數器為0,對象就滿足了垃圾收集的條件。
基於引用計數器的垃圾收集器運行較快,不會長時間中斷程序執行,適宜地必須 實時運行的程序。但引用計數器增加了程序執行的開銷,因為每次對象賦給新的變數,計數器加1,而每次現有對象出了作用域生,計數器減1。
2、tracing演算法(Tracing Collector)
tracing演算法是為了解決引用計數法的問題而提出,它使用了根集的概念。基於tracing演算法的垃圾收集器從根集開始掃描,識別出哪些對象可達,哪些對象不可達,並用某種方式標記可達對象,例如對每個可達對象設置一個或多個位。在掃描識別過程中,基於tracing演算法的垃圾收集也稱為標記和清除(mark-and-sweep)垃圾收集器.
3、compacting演算法(Compacting Collector)
為了解決堆碎片問題,基於tracing的垃圾回收吸收了Compacting演算法的思想,在清除的過程中,演算法將所有的對象移到堆的一端,堆的另一端就變成了一個相鄰的空閑內存區,收集器會對它移動的所有對象的所有引用進行更新,使得這些引用在新的位置能識別原來 的對象。在基於Compacting演算法的收集器的實現中,一般增加句柄和句柄表。
4、ing演算法(Coping Collector)
該演算法的提出是為了克服句柄的開銷和解決堆碎片的垃圾回收。它開始時把堆分成 一個對象 面和多個空閑面, 程序從對象面為對象分配空間,當對象滿了,基於coping演算法的垃圾 收集就從根集中掃描活動對象,並將每個 活動對象復制到空閑面(使得活動對象所佔的內存之間沒有空閑洞),這樣空閑面變成了對象面,原來的對象面變成了空閑面,程序會在新的對象面中分配內存。
一種典型的基於coping演算法的垃圾回收是stop-and-演算法,它將堆分成對象面和空閑區域面,在對象面與空閑區域面的切換過程中,程序暫停執行。
5、generation演算法(Generational Collector)
stop-and-垃圾收集器的一個缺陷是收集器必須復制所有的活動對象,這增加了程序等待時間,這是coping演算法低效的原因。在程序設計中有這樣的規律:多數對象存在的時間比較短,少數的存在時間比較長。因此,generation演算法將堆分成兩個或多個,每個子堆作為對象的一代(generation)。由於多數對象存在的時間比較短,隨著程序丟棄不使用的對象,垃圾收集器將從最年輕的子堆中收集這些對象。在分代式的垃圾收集器運行後,上次運行存活下來的對象移到下一最高代的子堆中,由於老一代的子堆不會經常被回收,因而節省了時間。
6、adaptive演算法(Adaptive Collector)
在特定的情況下,一些垃圾收集演算法會優於其它演算法。基於Adaptive演算法的垃圾收集器就是監控當前堆的使用情況,並將選擇適當演算法的垃圾收集器。
⑥ 各種編程語言的實現都採用了哪些垃圾回收演算法
從各種垃圾收集演算法最基本的運行方式來說,大概可以分成三個類型:
1. 引用計數(reference counting):
基本思路是為每個對象加一個計數器,記錄指向這個對象的引用數量。每次有一個新的引用指向這個對象,計數器加一;反之每次有一個指向這個對象引用被置空或者指向其他對象,計數器減一。當計數器變為 0 的時候,自動刪除這個對象。
引用計數的優點是 1)相對簡單,不需要太多運行時(run-time)的支持,可以在原生不支持 GC 的語言里實現。2)對象會在成為垃圾的瞬間被釋放,不會給正常程序的執行帶來額外中斷。它的死穴是循環引用,對象 A 包含一個引用指向對象 B ,同時對象 B 包含一個引用指向對象 A,計數器就抓瞎了。另外,引用計數對正常程序的執行性能有影響(每次引用賦值都要改計數器),特別是在多線程環境下(改計數器要加鎖同步)。
現在仍然主要採用引用計數的例子有 Apple 的 ARC,C++ 新標准里的 std::shared_ptr。
2. 標記-清掃(mark-sweep)。
基本思路是先按需分配,等到沒有空閑內存的時候從寄存器和程序棧上的引用出發,遍歷以對象為節點、以引用為邊構成的圖,把所有可以訪問到的對象打上標記,然後清掃一遍內存空間,把所有沒標記的對象釋放。
標記-清掃沒有無法處理循環引用的問題,不觸發 GC 時也不影響正常程序的執行性能。但它的問題是當內存耗盡觸發 GC 時,需要中斷正常程序一段時間來清掃內存,在內存大對象多的時候這個中斷可能很長。
採用或者部分採用標記-清掃的例子非常多,不一一列舉了。
3. 節點復制(ing)。
基本思路是把整個內存空間一分為二,不妨記為 A 和 B。所有對象的內存在 A 中分配,當 A 塞滿的時候,同樣從寄存器和程序棧上的引用出發,遍歷以對象為節點、以引用為邊構成的圖,把所有可以訪問到的對象復制到 B 去,然後對調 A 和 B 的角色。
相對於標記-清掃,節點復制的主要缺點是總有一半空間空閑著無法利用,另一個比較隱晦的缺點是它使用內存的方式與現有的內存換頁、Cache 換入換出機制有潛在的沖突。但它有個很大的優點: 所有的對象在內存中永遠都是緊密排列的,所以分配內存的任務變得極為簡單,只要移動一個指針即可。對於內存分配頻繁的環境來說,性能優勢相當大。另外,由於不需要清掃整個內存空間,所以如果內存中存活對象很少而垃圾對象很多的話(有些語言有這個傾向),觸發 GC 造成的中斷會小於標記-清掃。
同樣的,採用或者部分採用節點復制的例子也非常多,不一一列舉了。
⑦ 各種編程語言的實現都採用了哪些垃圾回收演算法
java語言:
. 採用Reference Counting的垃圾回收器
對於採用Reference Counting的垃圾回收器,系統為堆上每一個對象都維護一個計數器,當一個對象被創建並且別引用時,這個計數就被置為1。當有新的變數引用該對象,計數器進行自加運算。當一個引用超出作用范圍或者被賦予新值的時候,計數器進行自減運算。引用計數為0的對象,會被作為垃圾回收。當一個對象被回收,該對象所引用的對象的引用計數都會相應減少,因而,一個對象的回收有時會引起其它對象的回收。
Reference Counting方式的垃圾回收器,好處在於可以在很短的時間內運行,不會長時間的中斷普通的程序運行,因而在RealTime的系統中應用較為普遍。 Reference Counting方式的垃圾回收器,問題在於無法識別循環引用,比如父類對象還有子類引用的情況,即便父類和子類都已經不再能被訪問到(unreachable),引用計數也把它們清除。另外一個問題是引用計數器的加減運算會增加系統的計算開銷。 2. 採用Tracing的垃圾回收器
採用Tracing的垃圾回收器,遍歷由根節點(root nodes)出發的引用關系圖。在遍歷過程中遇到的對象,就被標記為活動。標記既可以是對應對象中的某一個標志,也可以是獨立的點陣圖中的標志。當遍歷完成以後,那些沒有被標記的對象,就被作為垃圾回收了。最基本Tracing演算法是"Mark and Sweep" 垃圾回收器的另外一個責任是清除堆上的碎片(Fragmentation)。對於Mark and Sweep的垃圾回收器通常有兩種實現方法來減少堆上的碎片: 壓縮(Compacting)和拷貝(Copying)
在編程語言Python中,使用也是引用計數演算法。
節點拷貝演算法
節點拷貝演算法是把整個堆分成兩個半區(From,To), GC的過程其實就是把存活對象從一個半區From拷貝到另外一個半區To的過程,而在下一次回收時,兩個半區再互換角色。在移動結束後,再更新對象的指針引用。
⑧ 三種聚類方法:層次、K均值、密度
一、層次聚類
1)距離和相似系數
r語言中使用dist(x, method = "euclidean",diag = FALSE, upper = FALSE, p = 2) 來計算距離。其中x是樣本矩陣或者數據框。method表示計算哪種距離。method的取值有:
euclidean 歐幾里德距離,就是平方再開方。
maximum 切比雪夫距離
manhattan 絕對值距離
canberra Lance 距離
minkowski 明科夫斯基距離,使用時要指定p值
binary 定性變數距離.
定性變數距離: 記m個項目裡面的 0:0配對數為m0 ,1:1配對數為m1,不能配對數為m2,距離=m1/(m1+m2);
diag 為TRUE的時候給出對角線上的距離。upper為TURE的時候給出上三角矩陣上的值。
r語言中使用scale(x, center = TRUE, scale = TRUE) 對數據矩陣做中心化和標准化變換。
如只中心化 scale(x,scale=F) ,
r語言中使用sweep(x, MARGIN, STATS, FUN="-", ...) 對矩陣進行運算。MARGIN為1,表示行的方向上進行運算,為2表示列的方向上運算。STATS是運算的參數。FUN為運算函數,默認是減法。下面利用sweep對矩陣x進行極差標准化變換
?
1
2
3
>center <-sweep(x, 2, apply(x, 2, mean)) #在列的方向上減去均值。
>R <-apply(x, 2, max) -apply(x,2,min) #算出極差,即列上的最大值-最小值
>x_star <-sweep(center, 2, R, "/") #把減去均值後的矩陣在列的方向上除以極差向量
?
1
2
3
>center <-sweep(x, 2, apply(x, 2, min)) #極差正規化變換
>R <-apply(x, 2, max) -apply(x,2,min)
>x_star <-sweep(center, 2, R, "/")
有時候我們不是對樣本進行分類,而是對變數進行分類。這時候,我們不計算距離,而是計算變數間的相似系數。常用的有夾角和相關系數。
r語言計算兩向量的夾角餘弦:
?
1
2
y <-scale(x, center =F, scale =T)/sqrt(nrow(x)-1)
C <-t(y) %*%y
相關系數用cor函數
2)層次聚類法
層次聚類法。先計算樣本之間的距離。每次將距離最近的點合並到同一個類。然後,再計算類與類之間的距離,將距離最近的類合並為一個大類。不停的合並,直到合成了一個類。其中類與類的距離的計算方法有:最短距離法,最長距離法,中間距離法,類平均法等。比如最短距離法,將類與類的距離定義為類與類之間樣本的最段距離。。。
r語言中使用hclust(d, method = "complete", members=NULL) 來進行層次聚類。
其中d為距離矩陣。
method表示類的合並方法,有:
single 最短距離法
complete 最長距離法
median 中間距離法
mcquitty 相似法
average 類平均法
centroid 重心法
ward 離差平方和法
?
1
2
3
4
5
6
7
8
> x <-c(1,2,6,8,11) #試用一下
> dim(x) <-c(5,1)
> d <-dist(x)
> hc1 <-hclust(d,"single")
> plot(hc1)
> plot(hc1,hang=-1,type="tirangle") #hang小於0時,樹將從底部畫起。
#type = c("rectangle", "triangle"),默認樹形圖是方形的。另一個是三角形。
#horiz TRUE 表示豎著放,FALSE表示橫著放。
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
> z <-scan()
1: 1.0000.8460.8050.8590.4730.3980.3010.382
9: 0.8461.0000.8810.8260.3760.3260.2770.277
17: 0.8050.8811.0000.8010.3800.3190.2370.345
25: 0.8590.8260.8011.0000.4360.3290.3270.365
33: 0.4730.3760.3800.4361.0000.7620.7300.629
41: 0.3980.3260.3190.3290.7621.0000.5830.577
49: 0.3010.2770.2370.3270.7300.5831.0000.539
57: 0.3820.4150.3450.3650.6290.5770.5391.000
65:
Read 64items
> names
[1] "shengao""shoubi""shang""xia""tizhong"
[6] "jingwei""xiongwei""xiongkuang"
> r <-matrix(z,nrow=8,dimnames=list(names,names))
> d <-as.dist(1-r)
> hc <-hclust(d)
> plot(hc)
然後可以用rect.hclust(tree, k = NULL, which = NULL, x = NULL, h = NULL,border = 2, cluster = NULL)來確定類的個數。 tree就是求出來的對象。k為分類的個數,h為類間距離的閾值。border是畫出來的顏色,用來分類的。
?
1
2
3
> plot(hc)
> rect.hclust(hc,k=2)
> rect.hclust(hc,h=0.5)
result=cutree(model,k=3) 該函數可以用來提取每個樣本的所屬類別
二、動態聚類k-means
層次聚類,在類形成之後就不再改變。而且數據比較大的時候更占內存。
動態聚類,先抽幾個點,把周圍的點聚集起來。然後算每個類的重心或平均值什麼的,以算出來的結果為分類點,不斷的重復。直到分類的結果收斂為止。r語言中主要使用kmeans(x, centers, iter.max = 10, nstart = 1, algorithm =c("Hartigan-Wong", "Lloyd","Forgy", "MacQueen"))來進行聚類。centers是初始類的個數或者初始類的中心。iter.max是最大迭代次數。nstart是當centers是數字的時候,隨機集合的個數。algorithm是演算法,默認是第一個。
?
使用knn包進行Kmean聚類分析
將數據集進行備份,將列newiris$Species置為空,將此數據集作為測試數據集
> newiris <- iris
> newiris$Species <- NULL
在數據集newiris上運行Kmean聚類分析, 將聚類結果保存在kc中。在kmean函數中,將需要生成聚類數設置為3
> (kc <- kmeans(newiris, 3))
K-means clustering with 3 clusters of sizes 38, 50, 62: K-means演算法產生了3個聚類,大小分別為38,50,62.
Cluster means: 每個聚類中各個列值生成的最終平均值
Sepal.Length Sepal.Width Petal.Length Petal.Width
1 5.006000 3.428000 1.462000 0.246000
2 5.901613 2.748387 4.393548 1.433871
3 6.850000 3.073684 5.742105 2.071053
Clustering vector: 每行記錄所屬的聚類(2代表屬於第二個聚類,1代表屬於第一個聚類,3代表屬於第三個聚類)
[1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
[37] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
[73] 2 2 2 2 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 3 3 3 3 2 3
[109] 3 3 3 3 3 2 2 3 3 3 3 2 3 2 3 2 3 3 2 2 3 3 3 3 3 2 3 3 3 3 2 3 3 3 2 3
[145] 3 3 2 3 3 2
Within cluster sum of squares by cluster: 每個聚類內部的距離平方和
[1] 15.15100 39.82097 23.87947
(between_SS / total_SS = 88.4 %) 組間的距離平方和佔了整體距離平方和的的88.4%,也就是說各個聚類間的距離做到了最大
Available components: 運行kmeans函數返回的對象所包含的各個組成部分
[1] "cluster" "centers" "totss" "withinss"
[5] "tot.withinss" "betweenss" "size"
("cluster"是一個整數向量,用於表示記錄所屬的聚類
"centers"是一個矩陣,表示每聚類中各個變數的中心點
"totss"表示所生成聚類的總體距離平方和
"withinss"表示各個聚類組內的距離平方和
"tot.withinss"表示聚類組內的距離平方和總量
"betweenss"表示聚類組間的聚類平方和總量
"size"表示每個聚類組中成員的數量)
創建一個連續表,在三個聚類中分別統計各種花出現的次數
> table(iris$Species, kc$cluster)
1 2 3
setosa 0 50 0
versicolor 2 0 48
virginica 36 0 14
根據最後的聚類結果畫出散點圖,數據為結果集中的列"Sepal.Length"和"Sepal.Width",顏色為用1,2,3表示的預設顏色
> plot(newiris[c("Sepal.Length", "Sepal.Width")], col = kc$cluster)
在圖上標出每個聚類的中心點
〉points(kc$centers[,c("Sepal.Length", "Sepal.Width")], col = 1:3, pch = 8, cex=2)
三、DBSCAN
動態聚類往往聚出來的類有點圓形或者橢圓形。基於密度掃描的演算法能夠解決這個問題。思路就是定一個距離半徑,定最少有多少個點,然後把可以到達的點都連起來,判定為同類。在r中的實現
dbscan(data, eps, MinPts, scale, method, seeds, showplot, countmode)
其中eps是距離的半徑,minpts是最少多少個點。 scale是否標准化(我猜) ,method 有三個值raw,dist,hybird,分別表示,數據是原始數據避免計算距離矩陣,數據就是距離矩陣,數據是原始數據但計算部分距離矩陣。showplot畫不畫圖,0不畫,1和2都畫。countmode,可以填個向量,用來顯示計算進度。用鳶尾花試一試
?
1
2
3
4
5
6
7
8
9
10
11
> install.packages("fpc", dependencies=T)
> library(fpc)
> newiris <-iris[1:4]
> model <-dbscan(newiris,1.5,5,scale=T,showplot=T,method="raw")# 畫出來明顯不對 把距離調小了一點
> model <-dbscan(newiris,0.5,5,scale=T,showplot=T,method="raw")
> model #還是不太理想……
dbscan Pts=150MinPts=5eps=0.5
012
border 34518
seed 04053
total 344571
⑨ jvm垃圾回收有哪些演算法
1.堆的分代和區域
(年輕代)Young Generation(eden、s0、s1 space) Minor GC
(老年代)Old Generation (Tenured space) Major GC|| Full GC
(永久代)Permanent Generation (Permanent space)【方法區(method area)】 Major GC
本地化的String從JDK 7開始就被移除了永久代(Permanent Generation )
JDK 8.HotSpot JVM開始使用本地化的內存存放類的元數據,這個空間叫做元空間(Metaspace)
2.判斷對象是否存活(哪些是垃圾對象)
1.引用計數(ReferenceCounting):對象有引用計數屬性,增加一個引用計數加1,減少一個引用計數減1,計數為0時可回收。(無法解決對象相互循環引用的問題)
2.根搜索(GC Roots Tracing):GCRoot對象作為起始點(根)。如果從根到某個對象是可達的,則該對象稱為「可達對象」(存活對象,不可回收對象)。否則就是不可達對象,可以被回收。
下圖中,對象Object6、Object7、Object8雖然互相引用,但他們的GC Roots是不可到達的,所以它們將會被判定為是可回收的對象
3.垃圾收集演算法
1.標記-清除(Mark-Sweep)演算法:
標記清除演算法分為「標記」和「清除」兩個階段:首先標記出需要回收的對象,標記完成之後統一清除對象。
缺點:
1、標記和清除效率不高;
2、產生大量不連續的內存碎片,導致有大量內存剩餘的情況下,由於,沒有連續的空間來存放較大的對象,從而觸發了另一次垃圾收集動作。
2.復制(Copying)演算法:
將可用內存容量劃分為大小相等的兩塊,每次只使用其中的一塊。當這一塊用完之後,就將還存活的對象復制到另外一塊上面,然後在把已使用過的內存空間一次清理掉。這樣使得每次都是對其中的一塊進行內存回收
⑩ 各種編程語言的實現都採用了哪些垃圾回收演算法
java語言: . 採用Reference Counting的垃圾回收器 對於採用Reference Counting的垃圾回收器,系統為堆上每一個對象都維護一個計數器,當一個對象被創建並且別引用時,這個計數就被置為1。當有新的變數引用該對象,計數器進行自加運算。當一個引用超出作用范圍或者被賦予新值的時候,計數器進行自減運算。引用計數為0的對象,會被作為垃圾回收。當一個對象被回收,該對象所引用的對象的引用計數都會相應減少,因而,一個對象的回收有時會引起其它對象的回收。 Reference Counting方式的垃圾回收器,好處在於可以在很短的時間內運行,不會長時間的中斷普通的程序運行,因而在RealTime的系統中應用較為普遍。 Reference Counting方式的垃圾回收器,問題在於無法識別循環引用,比如父類對象還有子類引用的情況,即便父類和子類都已經不再能被訪問到(unreachable),引用計數也把它們清除。另外一個問題是引用計數器的加減運算會增加系統的計算開銷。 2. 採用Tracing的垃圾回收器 採用Tracing的垃圾回收器,遍歷由根節點(root nodes)出發的引用關系圖。在遍歷過程中遇到的對象,就被標記為活動。標記既可以是對應對象中的某一個標志,也可以是獨立的點陣圖中的標志。當遍歷完成以後,那些沒有被標記的對象,就被作為垃圾回收了。最基本Tracing演算法是"Mark and Sweep" 垃圾回收器的另外一個責任是清除堆上的碎片(Fragmentation)。對於Mark and Sweep的垃圾回收器通常有兩種實現方法來減少堆上的碎片: 壓縮(Compacting)和拷貝(Copying) 在編程語言Python中,使用也是引用計數演算法。 節點拷貝演算法 節點拷貝演算法是把整個堆分成兩個半區(From,To), GC的過程其實就是把存活對象從一個半區From拷貝到另外一個半區To的過程,而在下一次回收時,兩個半區再互換角色。在移動結束後,再更新對象的指針引用。