垃圾回收基于“對象不再使用”的原則,自動檢測并回收不再被引用的對象。JVM通過跟蹤對象的引用關系來判斷對象是否仍在使用中。當一個對象沒有任何引用指向它時,垃圾回收器就會將其標記為可回收對象。
垃圾回收的工作機制
標記-清除(Mark-Sweep)算法:這是最基本的垃圾回收算法,分為兩個階段,首先標記出所有存活的對象,然后清除所有未被標記的對象。但這種算法可能會導致內存碎片化。
復制(Copying)算法:將內存分為兩個相等的區域,當一塊區域被填滿時,垃圾回收器將存活的對象復制到另一塊區域,然后清除原區域的所有對象。這種算法可以避免內存碎片化,但會浪費一半的內存空間。
標記-壓縮(Mark-Compact)算法:結合了標記-清除和復制算法的優點,標記存活對象,然后將所有存活對象壓縮到一塊連續的內存區域,并直接清除邊界以外的內存。這樣可以避免內存碎片化,同時節省了內存空間。
分代收集(Generational)算法:根據對象的存活周期將內存分為新生代和老生代。新生代通常采用復制算法,頻繁地回收新生代;老生代則采用標記-清除或標記-壓縮算法,較少地進行垃圾回收。這種算法可以顯著提高垃圾回收的效率。
垃圾回收的優化實踐
1.調整堆內存大小:根據應用的特點和需求,合理設置堆內存的大小,可以避免頻繁的垃圾回收和OutOfMemoryError異常。
2.對象引用優化:盡量避免全局變量和靜態變量持有對象引用,以減少被標記為存活的對象數量。
3.并發編程與垃圾回收:在多線程環境下,合理使用并發工具類(如java.util.concurrent包中的類),以減少線程間的對象共享,降低垃圾回收的負擔。
4.避免大對象和長期存活的對象:大對象和長期存活的對象會占用大量的堆內存,增加垃圾回收的負擔。盡可能地減小對象的大小或者縮短對象的存活周期。
5.監控與調優:使用JVM提供的監控工具(如jconsole、jvisualvm等)監控垃圾回收的狀態和性能指標,根據實際情況進行調優。
JVM的內存區域和常見GC
內存主要被分為三塊:新生代(Youn Generation)、舊生代(Old Generation)、持久代.
常見的GC算法:復制、標記-清除和標記-壓縮
引用計數法 (java沒有采用)
- 引用計數算法(Reference Counting)比較簡單,對每個對象保存一個整型 的引用計數器屬性。用于記錄對象被引用的情況。
- 對于一個對象A,只要有任何一個對象引用了A,則A的引用計數器就加1;當引用失效時,引用計數器就減1。只要對象A的引用計數器的值為0,即表示對象A不可能再被使用,可進行回收。
可達性分析算法
- 可達性分析算法是以根對象集合(GCRoots)為起始點,按照從上至下的方式搜索被根對象集合所連接的目標對象是否可達。
- ?使用可達性分析算法后,內存中的存活對象都會被根對象集合直接或間接連接著,搜索所走過的路徑稱為引用鏈(Reference Chain)
- ?如果目標對象沒有任何引用鏈相連,則是不可達的,就意味著該對象己經死亡,可以標記為垃圾對象。
- ?在可達性分析算法中,只有能夠被根對象集合直接或者間接連接的對象才是存活對象。