JVM之GC趣解
每天下班回家後,相信很多人都是到家後,外衣脫了隨便一扔,鞋脫了踢到一邊,揹包也是隨手一放,鑰匙、錢包、手機也是一樣。其原因就是我們要最快的進入回家的狀態--躺下,休息或者做飯,吃東西,看電視總之一切讓自己舒服。不管其他的,只要達到自己的目的,用計算機的原理來說這叫效率(時間複雜度最低),不接受反駁。
但是帶來一個問題就是,時間長了,屋裡一定會非常的亂,地上有很多衣服,日用品,當然還有零食袋等生活垃圾。
如果不清理,在時間長了,垃圾佔用了大量的生活空間,我們的生活空間越來越不夠用了(這就是可使用的記憶體變小了---記憶體洩漏),直到有一天,當我們下班回到家的時候,腳都放不下了,這個家我們就回不去了,也就無法使用了(這就是記憶體不夠用了---記憶體溢位OOM)。
為了防止這樣,JVM就有了垃圾回收機制。
1.Serial GC ,單執行緒GC。
如果把你的家比作一個堆記憶體,把你自己比作一個Seriale GC,你會怎麼做呢?
如果恰好你的家有兩個屋子,一個客廳,一個臥室。是不是可以這樣呢:首先,做清理前的準備,先把其中一個屋子(臥室)清理乾淨,日常你只用另一個屋子(客廳)。等到客廳的非常亂的時候,作為Seriale GC的你可以先看下客廳裡那些東西是你想要的(比如,衣服,鞋子,包等)把,這些東西按照類別整理:
1.衣服放到你的乾淨的空間(臥室廳),並且疊好,摞在一起;
2.鞋子也放到你的乾淨的空間(臥室)拖鞋跟拖鞋放一起,皮鞋跟皮鞋放一起,布鞋跟布鞋放一起,擺放整齊;
3.包包,也是放到臥室,根據其用途,分門別類放整齊;
當把需要的東西,已經區分出來,並放到乾淨的空間(臥室)後,這時候,你就可以大刀闊斧的清理垃圾了,(拋去需要的,其他的都是不需要的,無論是零食袋,還是灰塵等,不用區分,直接一股腦的清理乾淨)因為省去了區分,整理這個步驟,垃圾回收還是很快的打掃完了,這下,我們的客廳又是一個乾淨的空間。以後當我們的臥室,又亂的時候,我們就可以以同樣的方式將有用的東西整理到客廳,然後打掃臥室。如此往復,日日月月,開心的過一輩子……
這就是垃圾回收器的 複製-整理 演算法。
但是又有一個問題,複製-整理演算法,能滿足所有情況麼?是否可以通過通過這一招吃遍天下?
當然不會,這種演算法只是適合,需要複製-整理的東西比較小部分的時候,當大部分的東西都需要 複製-整理的時候,這個演算法就得不償失了。打個比方,當你的客廳比較亂的時候,僅僅是將衣服,鞋子,包包,整理下放到臥室,是不是很容易。如果要是將沙發,茶几,冰箱,彩電,魚缸,等全都要放到臥室裡,然後僅僅是清理下零食袋,以及一小點垃圾那麼,這樣做是不是太傻了。用計算機的術語說,效能浪費嚴重。
那需要清理的東西佔小部分,大部分都是不需要清理的,用什麼辦法呢?
試想一下,這個就是我們生活中大多數的情況,因為我們每次打掃衛生,整理的垃圾都是佔少部分,大部分比如說像是,沙發,茶几,冰箱等家電,都是不需要清理的東西,當然你是國民老公那就例外了。
只需要將少部分垃圾清理,比如說,零食袋,將他放到垃圾袋子裡跟其他垃圾一併清理出屋子。這就是 標記-清除 演算法。找到零食袋放到一邊等著清理(這就是標記),將垃圾一併清理出屋子(這就是清除)。
在我們JAVA 堆記憶體裡,新生代Eden,裡大部分物件都是要回收的,所以用 複製-整理 演算法;老年的 Old 裡大部分物件是不需要回收的,所以用 標記-清除 演算法。
還有一個要注意的是,如果你是Seriale GC,那麼在你收拾屋子的時候,你將無法 睡覺、洗衣服、做飯,幹其他的事情,只能一心一意的收拾屋子,直到把屋子收拾完以後才能做其他的事情。這個事情放到JVM裡就叫做STW(stop the world)。暫停所有的使用者執行緒,只做垃圾的回收。當然這個對於效能有很大的影響。試想一下,當N多個使用者在秒殺一個東西的時候,這時候你的JVM 在STW,導致伺服器一段時間裡屬於不可用狀態。會產生什麼樣的後果,那就不敢想了。
&n