Java 語言與C語言中垃圾回收的不同方式

來源:文萃谷 6.66K

導語:垃圾回收是一種動態儲存管理技術,它自動地釋放不再被程式引用的物件,按照特定的垃圾回收演算法來實現資源自動回收。下面就由小編為大家介紹一下Java 語言C語言中垃圾回收的不同方式,歡迎大家閱讀!

Java 語言與C語言中垃圾回收的不同方式

  1 Java語言中的垃圾回收機制

時下最流行的程式語言Java擁有自己的垃圾回收機制。實際上,Java語言來自於C++語言。但Java語言避免了C++語言中複雜的結構,成功克服了多重繼承機制存在的二義性問題;Java的垃圾回收機制顯著地提高了程式的效率,降低了複雜度。由於有垃圾回收機制,使Java中的物件不再有“作用域”的概念,而只有物件的引用才有“作用域”。垃圾回收器是一種動態儲存分配器,它自動釋放程式不再需要的已分配堆塊,並且能夠壓縮排程堆塊所需要的記憶體空間。垃圾收集是指自動回收不被程式佔用的分配堆塊的過程。在一個支援垃圾收集的系統中,應用顯式分配堆塊,但是從不顯式釋放堆塊。垃圾回收器一般是作為一個低級別的獨立執行緒執行,不可預知的情況下對記憶體堆中已經廢除的或者長時間沒有使用的物件進行清除和回收,而程式設計師不能實時的呼叫垃圾回收器對某個物件或所有物件進行垃圾回收。

Java程式設計人員不用擔心記憶體管理,垃圾收集器會自動進行管理。但是垃圾回收機制通常只在滿足兩個條件時才執行:即有物件要求回收並且系統需要回收。那麼,Java的垃圾回收機制是如何操作的呢?下面我們來了解一下Java垃圾回收機制的演算法。

1.1 引用計數法

引用計數法,是最原始也是被很多語言所廣泛應用的垃圾回收演算法。其主旨是給堆中每一個物件都設定一個引用計數,當其被賦值給物件的引用時,其引用計數加1,當其物件的引用超出生命週期或者被新值賦值時,引用減1,當其引用計數為0時,即可被系統回收。

1.2 跟蹤演算法

引用計數法一種重要的問題在於當物件間出現迴圈引用的時候,其計數永遠不會為0,既永遠不會被回收。跟蹤演算法解決了這一問題,跟蹤演算法是採用從根集開始掃描來識別物件是否可達。標記可達的物件,將不可達的物件也就是未標記的`物件清除,又稱標記和清除演算法。

1.3 壓縮演算法

跟蹤演算法的一個問題就是清除物件後的記憶體空間變成了堆碎片,不便於再次利用。為了解決這個問題,引入了壓縮演算法。所謂壓縮演算法就是在清除的過程中,將所有物件移動到堆的一端,而本來的那端就變成了一段空閒記憶體區,收集器要對移動物件的所有引用進行更新。

1.4 複製演算法

壓縮演算法的問題在於每次對物件引用更新的時候都產生了冗餘的控制代碼和控制代碼表。為此,又引入了複製演算法,複製演算法的主旨是在一開始就把堆分成一個物件面和多個空閒面,將物件面的記憶體空間分配給程式,當空間滿了的時候,利用追蹤演算法的機理掃描活動物件,但並不清除,而是將每個活動物件複製到空閒面,這樣空閒面和物件面就互換了。

1.5 分代演算法

複製演算法又稱停止和複製演算法,在其物件面和空閒面切換的過程中程式要暫停執行,這樣大大降低了程式執行的效率。分代演算法正好可以解決這個問題。分代演算法基於程式中大多數物件生命週期較短,少數較長的特點,將堆分成多個,每個子堆作為物件的一代。垃圾收集器從最新建立的物件中,將活躍的物件移到最高代的子堆中,這樣老一代的子堆不會被經常回收,利用這種分代式的方法,節約了時間。

1.6 自適應演算法

自適應法,就是指根據特殊情況,採取特殊演算法,通過監控當前堆的使用情況選擇適當的演算法進行垃圾回收。

垃圾回收要佔用時間,因此,Java執行時,系統只在需要的時候才使用它,而程式設計者本身無法知道回收發生的準確時間。但如果需要垃圾回收,程式設計者也可以隨時呼叫下面的方法之一:

();

untime()();

  2 C語言中的垃圾回收

C語言憑藉其簡潔緊湊、資料型別豐富、程式執行效率高等特點,擁有著大量的程式設計愛好者,而眾多IT界牛人也說,精通C語言,就等於精通程式設計。然而C語言實際上是沒有垃圾回收機制的,那麼被如此廣泛應用的程式語言如何來處理其垃圾回收問題呢?

答案就是使用保守垃圾收集器並呼叫free()函式。像Java語言中,垃圾收集器對於指標的建立和使用有著嚴格的控制,所以其能回收所有的垃圾記憶體,而諸如C這樣的語言,垃圾收集器不能被嚴格控制,則稱之為保守垃圾收集器。

那麼在C語言中的垃圾收集器是如何工作的呢?

C語言支援垃圾回收系統,如前文所說,在支援垃圾收集的系統中,應用顯示分配堆塊,但不顯式地釋放。而在C語言程式中,應用程式呼叫malloc()函式但是從不呼叫free()函式,取而代之的是使用垃圾收集器週期性識別垃圾堆塊,並需要程式設計人員呼叫free()函式,將這些垃圾堆塊放回到空閒連結串列中。因此,只依靠垃圾收集器是無法做到垃圾記憶體的全部釋放。

下面我們用有向圖的概念理解儲存器,當存在一條從任意根節點出發併到達Q點的有向路徑時,我們說節點Q是可達的。Java語言中的垃圾回收器,能夠準確的標記每個節點是否可達,並將不可達的節點回收,放入空連結串列中。而C語言的垃圾回收器,就是我們所說的保守垃圾回收器,能夠正確地標記可達的節點,但一些不可達的節點卻有可能被錯誤地標記為可達。從而,被錯誤標記的節點,將永遠不會被回收。可想而知,當系統中的記憶體被錯誤標記所佔滿時,系統將無法再執行。

下面我們來看,垃圾收集器如何為C程式將一個保守的收集器加入到已存在的malloc()函式中,如圖1所示。

垃圾收集器作為一個應用並行的獨立執行緒,不斷地更新有向圖和回收垃圾。無論應用程式何時需要記憶體空間,系統都會呼叫malloc()函式,如果malloc()函式找不到可用的記憶體分配快,那麼它就呼叫垃圾收集器,垃圾收集器識別出垃圾塊,並通過呼叫free()函式將它們返回給堆塊。這裡的關鍵在於,垃圾收集器代替了應用程式去呼叫free()函式,當對垃圾收集的呼叫返回時,malloc()函式想要發現一個可用的空閒塊。如果還是不成功,它就向作業系統請求額外的儲存器。最後,如果成功,malloc()函式返回一個指向請求塊的指標,如果不成功就返回一個空指標。

  3 小結

綜上所述,不同語言對於垃圾回收的方式不同,但是不管是什麼語言,垃圾回收都有著重要的作用。所以,在程式設計學習中,尤其是程式設計入門階段應該養成呼叫記憶體釋放函式的好習慣,在每次佔用記憶體結束後,應主動釋放記憶體,這樣即節省記憶體空間,又提高系統效率。

熱門標籤