Grabage Collection:在系統運行過程當中佔據空間的無用對象在必定時間範圍內被及時清理來保證整個系統有足夠的內存空間來運行。java中GC的對象是堆和永久區。java
經常使用的GC算法算法
引用計數法(reference counting)性能優化
概念:對於一個對象A,只要有任何一個對象引用了A,則A的引用計數器就加1,當引用失效時,引用計數器就減1。只要對象A的引用計數器的值爲0,則對象A就不可能再被使用。多線程
出現的問題:①.引用和去引用伴隨加法和減法,影響性能。②.很難處理垃圾對象的循環引用。下面一段代碼說明循環引用問題:架構
package jvm;/** * GC引用計數法Demo * @author Administrator * */public class JvmGcDemo { public static void main(String[] args) { GcObject g1 = new GcObject();//棧中建立變量g1指向(引用)new出對象GcObject1(堆中),此時GcObject1的引用計數爲1 GcObject g2 = new GcObject();//棧中建立變量g2指向(引用)new出對象GcObject2(堆中),此時GcObject2的引用計數爲1 g1.o = g2;//GcObject1的引用計數再加1,引用計數=2 g2.o = g1;//GcObject2的引用計數再加1,引用計數=2 g1 = null;//GcObject1的引用計數減1,引用計數=1 g2 = null;//GcObject2的引用計數減1,引用計數=1 } } class GcObject{ public Object o; }1234567891011121314151617181920
看上面代碼流程發現GcObject1和GcObject2循環引用,引用計數都爲1,最後引用計數法沒法回收這兩個無用的對象。併發
在eclipse中初始化配置jvm參數,最大使用內存20M,最小使用內存5M:-Xmx20m -Xms5m;修改上段代碼,用System.gc()進行GC,即下面代碼:eclipse
package jvm;/** * GC引用計數法Demo * @author Administrator * */public class JvmGcDemo { public static void main(String[] args) { printMemory(1);//打印內存 free memory:4.719520568847656M,約5M GcObject g1 = new GcObject();//棧中建立變量g1指向(引用)new出對象GcObject1(佔用1M堆內存),此時GcObject1的引用計數爲1 GcObject g2 = new GcObject();//棧中建立變量g2指向(引用)new出對象GcObject2(佔用1M堆內存),此時GcObject2的引用計數爲1 printMemory(2);//打印內存發現free memory:2.7194900512695312M = 4.719520568847656M - 2M g1.o = g2;//GcObject1的引用計數再加1,引用計數=2 g2.o = g1;//GcObject2的引用計數再加1,引用計數=2 g1 = null;//GcObject1的引用計數減1,引用計數=1 g2 = null;//GcObject2的引用計數減1,引用計數=1 System.gc();//進行GC printMemory(3);//free memory3:4.922454833984375M 說明GcObject1和GcObject2被回收 } /** * 打印內存 */ public static void printMemory(int i){ //打印空閒堆內存 System.out.println("free memory"+i+":"+Runtime.getRuntime().freeMemory()/1024.0/1024+"M"); System.out.println("---------------------------->"); } } class GcObject{ public Object o; byte[] by = new byte[1024*1024];//佔用1M內存}1234567891011121314151617181920212223242526272829303132
控制檯輸出:jvm
free memory1:4.75958251953125M分佈式
—————————->微服務
free memory2:2.7194137573242188M
—————————->
free memory3:4.922454833984375M
—————————->
發現GC後free memory3比free memory2增長了2M多一點(多出的部分是回收的其餘垃圾內存),free memory3與free memory1無明顯差異,說明對象GcObject1和GcObject2被回收,這是由於JVM沒有采用引用計數法進行回收垃圾。
標記-清除算法(mark-and-sweep)
概念:標記-清除算法是現代垃圾回收算法的思想基礎。是指在可使用的內存被耗盡的時候,GC線程就會被觸發並將程序暫停,進行標記-清除算法將垃圾回收,過程分爲兩個階段:標記階段和清除階段。在標記階段,首先經過根節點,標記全部從根節點開始的可達對象。所以,未被標記的對象就是未被引用的垃圾對象。而後,在清除階段,清除全部未被標記的對象。
出現的問題:①.標記和清除過程效率不高 ,並且在進行GC的時候,須要中止應用程序,這會致使用戶體驗很是差勁。②.標記清除以後會產生大量不連續的內存碎片。失效對象都是隨即的出如今內存的各個角落的,如今把它們清除以後,內存的佈局天然會亂七八糟。
標記-壓縮算法(mark-compact)
概念:標記-壓縮算法適合用於存活對象較多的場合,如老年代。它在標記-清除算法的基礎上作了一些優化。和標記-清除算法同樣,標記-壓縮算法也首先須要從根節點開始,對全部可達對象作一次標記。但以後,它並不簡單的清理未標記的對象,而是將全部的存活對象壓縮到內存的一端,以後,清理邊界外全部的空間。
出現的問題:標記-壓縮算法的缺點就是效率也不高,不只要標記全部存活對象,還要整理全部存活對象的引用地址。
複製算法(copying)
概念:將原有的內存空間分爲兩塊,每次只使用其中一塊,在垃圾回收時,將正在使用的內存中的存活對象複製到未使用的內存塊中,以後,清除正在使用的內存塊中的全部對象,交換兩個內存的角色,完成垃圾回收.
出現的問題:用空間換取時間,空間浪費,不適用於存活對象較多的場合,如老年代等。
分代收集算法(generational collecting)
概念:把對象分爲年輕代、年老代、持久代,對不一樣的生命週期使用不一樣的算法進行回收,通常新生代對象和小對象適合複製算法,老年代對象和大對象存活適合標記-清理或者標記-壓縮算法。
對象的可觸及性
可觸及的
從根節點能夠觸及到這個對象。根通常爲棧中引用的對象、方法區中靜態成員或者常量引用的對象(全局對象)、JNI方法棧中引用對象。
可復活的
一旦全部引用被釋放,就是可復活狀態,由於在finalize()中可能復活該對象。
不可觸及的
在finalize()以後,可能會進入不可觸及狀態,不可觸及的對象不可能復活,能夠回收。
GC參數
串行收集器
最古老、最穩定、效率高的收集器,缺點是可能會產生較長時間的停頓,她只使用一個線程去回收,沒有辦法發揮多核計算機的性能。
-XX:+UseSerialGC
新聲代和老年代使用串行回收,新生代使用複製算法、老年代使用標記-壓縮算法。
並行收集器
ParNew
-XX:UserParNewGC
新生代使用並行回收,老年代使用串行回收。
新生代的的並行回收採用複製算法,多線程回收(多核支持),可使用XX:ParallelGCThreads限制線程的數量。固然,多線程並不必定快。
Parallel
相似於ParNew,新聲代採用複製算法、老年代使用標記-壓縮算法,更加關注吞吐量。
-XX:+UseParallelGC 使用Parallel收集器和老年代串行。
-XX:+UserParalleOldGC 使用Paralle收集器老年代並行。
-XX:MaxGCPauseMills 最大停頓時間,單位毫秒,GC盡力保證收回時間不超過設定的值,但不是確定。
-XX:GCTimeRatio 在0-100中取值,表明垃圾收集時間佔總時間的比,默認99,表明最大容許1%的時間作GC。
CMS收集器
Concurrent Mark Sweep 併發(與用戶線程一塊兒執行)標記清除,這是一個老年代的收集器(新聲代使用的是ParNew),GC中應用線程停頓時間比較短,因此併發階段會下降吞吐量。
-XX:+UseConcMarkSweepGC
CMS收集器GC過程
初始標記
根能夠直接關聯到的對象,速度快
併發標記(和用戶線程一塊兒)
主要標記過程,標記所有對象
從新標記
因爲併發標記時,用戶線程依然運行,所以在正式清理前,再作修正
併發清除(和用戶線程一塊兒)
基於標記結果,直接清理對象
CMS收集器特色
儘量下降停頓
會影響系統總體吞吐量和性能。好比,在用戶線程運行過程當中,分一半CPU去作GC,系統性能在GC階段,反應速度就降低一半。
清理不完全。由於在清理階段,用戶線程還在運行,會產生新的垃圾,沒法清理。
不能在空間快滿時再清理,由於和用戶線程一塊兒運行。-XX:CMSInitiatingOccupancyFraction設置觸發GC的閾值,若是不幸內存預留空間不夠,就會引發concurrent mode failure。
CMS收集器經常使用參數
-XX:+UseCMSCompactAtFullCollection Full GC,進行一次整理,整理的過程是獨佔的,停頓時間較長。
-XX:+CMSFullGCsBeforeCompaction 設置幾回 Full GC後進行一次一次碎片整理。
-XX:ParallelCMSThreads 設定CMS的線程數量,通常約等於可用CPU的數量,不宜設置太大。
GC的參數整理
-XX:+UseSerialGC:在新生代和老年代使用串行收集器
-XX:SurvivorRatio:設置eden區大小和survivior區大小的比例
-XX:NewRatio:新生代和老年代的比
-XX:+UseParNewGC:在新生代使用並行收集器
-XX:+UseParallelGC :在新生代使用並行回收收集器
-XX:+UseParallelOldGC:老年代使用並行回收收集器
-XX:ParallelGCThreads:設置用於垃圾回收的線程數
-XX:+UseConcMarkSweepGC:新生代使用並行收集器,老年代使用CMS+串行收集器
-XX:ParallelCMSThreads:設定CMS的線程數量
-XX:CMSInitiatingOccupancyFraction:設置CMS收集器在老年代空間被使用多少後觸發
-XX:+UseCMSCompactAtFullCollection:設置CMS收集器在完成垃圾收集後是否要進行一次內存碎片的整理
-XX:CMSFullGCsBeforeCompaction:設定進行多少次CMS垃圾回收後,進行一次內存壓縮
-XX:+CMSClassUnloadingEnabled:容許對類元數據進行回收
-XX:CMSInitiatingPermOccupancyFraction:當永久區佔用率達到這一百分比時,啓動CMS回收
-XX:UseCMSInitiatingOccupancyOnly:表示只在到達閥值的時候,才進行CMS回收
在此我向你們推薦一個架構學習交流羣。交流學習羣號: 744642380, 裏面會分享一些資深架構師錄製的視頻錄像:有Spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化、分佈式架構等這些成爲架構師必備的知識體系。還能領取免費的學習資源,目前受益良