Java老師在期末復習大綱上出了一道關於JVM垃圾回收機制的題目,想要我們簡述一下JVM垃圾回收機制,與老師交流后,大概老師是希望通過與其他語言在垃圾回收對比,介紹一下Java在這方面的特點和處理過程,這里我搜索到一篇差不多內容的論文,這篇論文在內容上講的很淺,沒有深入到源碼和內部算法,大致了解一下即可。
在運用面向對象語言編寫的程序中,當某些對象不再被引用的時候,內存回收它占領的空間,以便空間能夠被后來的新對象所使用,以免造成內存泄露。C++與 Java 是這些年較為流行的面向對象語言,Java是由 C++發展出來的。 內存泄漏一般來講主要有兩種情況:第一種情況是在堆中分配的內存,在沒有將其釋放的時候,就將能訪問這塊內存的方式刪掉;第二種情況是在內存對象已經不需要的時候,仍舊保留着內存和它的訪問方式。 而出現第一種情況多是在 C++中,指針是C++中一種內置的數據類型,且發生的原因是所使用的指針出現了重新賦值的情況;第二種情況多出現在 Java 中,這也是 Java 內存泄露的主要情況。
垃圾回收機制是一種動態的存儲技術,它能夠自動釋放不再被程序引用的對象,按照特定的垃圾回收算法實現系統資源自動回收的功能。
Java 是一種跨平台,適合於分布式計算環境的純面向對象編程語言。 在 Java 中,程序員是通過關鍵字 new 來創建對象以及在堆(Heap)中為對象分配內存空間(基本數據類型除外),而對象的釋放是由 GC(Garbage Collection,垃圾回收器)決定和執行的。這種收支兩條線在很大程度上簡化了程序員的工作, 但 也 加 重 了 JVM (Java VirtualMachine,Java 虛擬機)的工作。 Java 並沒有明確指明 JVM 在進行垃圾回收時使用哪種垃圾回收算法,但是不管采用那種垃圾回收算法均要完成發現無用對象並回收被無用對象占用的內存空間的功能。 Java 中對內存對象的訪問采用的是引用方式,當 GC 跟蹤到某個對象沒有被
任何線程訪問時,該對象就要被刪除,就將其加入到垃圾回收隊列,但是進行垃圾回收的線程是一種低優先級的系統級線程,為此系統並不會馬上進行對象的消除, 而何時消除並釋放內存是無法預知的。 在Java 中一般是在 CPU 空閑或者是空間不足時自動進行垃圾回收,對於程序員來講, 是無法精准的控制垃圾回收的時機和回收的順序,哪怕是 Java 虛擬機拋出 OutOfMemoryError 異常, 或者是程序員調用了System.gc()方法請求 JVM 進行垃圾回收。
C++也是一種面向對象語言,但由於兼容了 C 我們通常認為它是一種半面向對象語言。 在 C++中內存的分配主要有三種方法:1)全局變量和靜態變量存儲在靜態存儲區中,生存的周期就是程序運行的周期,即當程序結束,才釋放這些存儲空間;2)函數內部的局部變量存儲在棧上,生存的周期就是該變量所在函數的運行周期,即函數調用結束后,這些存儲空間自動釋放。3)動態分配存儲空間,在 C 語言中通過malloc,free 來完成內存空間的分配與釋放, 在 C++中通過 new,delete來完成內存空間的分配與釋放, 生存周期是由 new 和 delete 來決定的。
在 C++中程序員運用 new 實現動態分配內存空間,分配后就需要負責這塊內存的整個生命周期。 從分配到使用再到最后的釋放,這樣的過程顯的很靈活,但同時也十分繁瑣,程序員很容易由於某種原因而忘記釋放內存,從而導致內存的泄露。 而 C++不像 Java 那樣有 GC自動實現垃圾回收,但為我們提供了智能指針來解決內存問題。 智能指針是一種像指針的 C++對象,它能夠在對象不使用的時候自己銷毀掉。
在 C++標准庫(std)中提供了一種智能指針 auto_ptr,實際上該智能指針是一種模板類,其工作原理是:通過 new 來分配內存空間構造一個對象,通過自動調用析構函數來完成對這段內存的釋放。 具體的實現是:auto_ptr 在構造時獲取對某個對象的所有權,在析構時釋放該對象,這樣可以提高代碼的安全性。
例如:
int * p=new int(0); auto_ptrap(p);
智能指針 ap 獲取了 p 的所有權, 從此我們不必關心應該何時釋放 p, 更不用擔心發生異常會有內存泄漏。 auto_ptr 智能指針使用簡單,方便靈活,除了在定義的時候與普通指針有一點區別以外,其他具體的使用與普通指針是一樣的,但是 auto_ptr 智能指針不能將數組作為參數以及不能將 auto_ptr 對象作為標准模板庫(STL)容器的元素使得它的使用並不是很廣泛。
Boost 庫 是 為 C++語言標准庫提供擴展的一些 C++程序庫的 總稱 ,Boost 庫為我們定義了多個不同智能指針來 管理不同的場景 ,shared_ptr 是使用最廣泛的智能指針。 shared_ptr 智能指針在內部維護一個引用計數器, 當有指針指向這塊內存區域時引用計數器加 1,反之減 1, 若沒有任何指針指向引用計數器為 0, 則釋放內存區域。shared_ptr 指針可以實現共享和轉移所有權, 同時它可以被 STL 的容器所使用,這一點與 auto_ptr 指針不同,還有一個更大的特點就是適合管理對象被若干個對象共享的復雜問題。 scoped_ptr 是 Boost 庫中最簡單的智能指針,當指針離開作用域時釋放相關的資源,該指針不能共享指針的所有權也不能轉移所有權,即內存地址只能給聲明的變量使用而不能給其他使用。 Boost 庫還有很多其他智能指針,這里不再一一敘述,總之在 C++中不論使用標准庫中的智能指針,還是 Boost 庫中的智能指針,在一定的條件下可以實現垃圾回收,同時智能指針使用起來比較簡單,能夠有效地解決內存泄露問題。
【參考文獻】
[1]Java 內存分配與釋放[OL]. http://wenku.baidu.com/view/c124098ccc22bcd126f
f0cd4.html.
[2]全面分析 Java 的垃圾回收機制[OL]. http://tech.qq.com/a/20060726/000329.htm.
[3]陳龍得,畢海濱.淺談在 C++中如何實現垃圾自動回收[J].電腦知識與技術,
2008,7:2007-2008.
[4]C++Boost 庫中的智能指針論 [OL]. http://blog.sina.com.cn/s/blog_6eb6c 4590
100n74y.html.
作者簡介:王艷娟(1979—),女,濟南職業學院教師。
