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