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

導語:垃圾回收是一種動態存儲管理技術,它自動地釋放不再被程序引用的對象,按照特定的垃圾回收算法來實現資源自動回收。下面就由小編爲大家介紹一下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 小結

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