Java垃圾回收器的工作原理
上課,老師照本宣科,實在難以理解,乾脆就看書裡的Java書,正好看了Java的垃圾回收器是如何工作的,覺得有必要記錄一下。
參考於 Java程式設計思想第四版(Thinking in Java)
1.垃圾回收器對於提高物件的建立速度,有明顯的效果
問題來了,垃圾回收是釋放物件,而關建立物件什麼事?
首先了解一下Java是如何在堆上分配記憶體的,Java使用“堆指標”,每分配一個物件,指標就往後移一位,類似於堆疊,這樣就達到了高速建立物件,但這樣的方法帶來了弊端,在堆疊中還可以出棧來釋放,在堆裡你沒有出棧啊,不一會堆(記憶體)就滿了,就要放磁碟上去,非常浪費時間。那麼這時候垃圾回收裝置就介入了,他幫助我們回收空間,並處理因為釋放物件而產生的碎片(因為有的物件可能比較小,釋放後就空了一塊記憶體,比如大小為5,但是其他物件的大小都在10以上,那麼這塊記憶體就是碎片了,別的物件根本就放不進去)。
有了垃圾回收器,所以java才能使用“堆指標”來建立物件,所以說垃圾回收器對建立速度有明顯的效果
2.Java垃圾回收器的具體機制
2.1 引用計數法
就是每個物件都有一個標誌,每次被引用1次就加1,如果引用為0,那麼就會去回收,但會有特殊情況,如果兩個物件在堆裡,互相引用,那麼使用這種方法就失效了,所以java中不用這種方法。
2.2停止-複製(stop-and-copy) 和 標記-清掃(mark-and-sweep)
這兩個思想是相同的,不同具體實現略有不同。這兩種方式需要程式暫停才能工作。
首先從堆疊或靜態儲存區開始,遍歷所有的引用,根據引用找到物件,在遍歷檢視找到物件中的引用,依次下去,這樣就避免的互相引用的問題,因為如果互相引用,那麼在堆疊中根本就不會出現
停止-複製就是在開闢一個堆,然後把“活”的引用複製到堆中,不過開闢堆實在太浪費,感覺就在把一個堆劃分成不同的塊,在塊中複製。
標記-清掃就是“活”的物件給個標記,先找出打好標記,然後在回收。
Java虛擬機器可以自適應切換兩種方法,因為如果在很少需要回收的物件時,如果還使用停止-複製未免也太浪費了,如果一直用標記-清掃,那麼就會產生很多的碎片,有很多碎片的時候就用停止-複製,因為複製到另一個塊中,程式自然會去把物件排列好。
注:如果一個大型物件佔了一個單獨的塊,那麼使用停止-複製的時候就不會複製,因為複製了也是一個一摸一樣的塊毫無意義。