Java是一種可以撰寫跨平臺應用軟件的面向對象的程序設計語言。Java 技術具有卓越的通用性、高效性、平臺移植性和安全性,廣泛應用于PC、數據中心、游戲控制臺、科學超級計算機、移動電話和互聯網,同時擁有全球最大的開發者專業社群。
給你學習路線:html-css-js-jq-javase-數據庫-jsp-servlet-Struts2-hibernate-mybatis-spring4-springmvc-ssh-ssm
前言
Java虛擬機的垃圾收集器是虛擬機內存的清道夫,它的存在讓Java開發人員能將更多精力投入到業務研發上。了解垃圾收集器,并利用好這個工具,能更好的保障服務穩定性。這篇文章通過分析Java虛擬機內存模型,介紹垃圾收集器常用算法和收集器類別,使得垃圾收集器的配置和使用變得不再遙不可及。
Java虛擬機內存模型
Java虛擬機內存可以劃分為:虛擬機棧、本地方法棧、JAVA堆內存、方法區(包含運行時常量池)、程序計數器、直接內存。
虛擬機棧
虛擬機棧是線程私有的,生命周期跟線程相同。也就是說一個線程被創建后,虛擬機為其分配了一個獨立的棧幀來存儲線程的局部變量、操作數、動態鏈接、方法出口等信息,當線程結束后,該棧幀也會被回收清理。
小編推薦一個學Java的學習裙【 七六零,二五零,五四一 】,無論你是大牛還是小白,是想轉行還是想入行都可以來了解一起進步一起學習!裙內有開發工具,很多干貨和技術資料分享!
本地方法棧
本地方法棧是虛擬機的native方法執行期間使用的一個棧幀。
Java堆內存
堆內存是被所有線程共享的一塊區域,用來存放對象實例和數組,屬于內存中最大的一塊區域,也是垃圾收集的主要區域。從垃圾收集的角度看,堆內存經常分為新生代和老年代。
方法區
方法區也是被所有線程共享的一塊區域,用來存儲被虛擬機加載的類信息、常量、靜態變量、JIT編譯后代碼等數據。也可以成為永久代。
程序計數器
程序計數器是線程私有的,作為當前線程所執行的字節碼的行號指示器,每個線程有一個程序計數器,用于記錄CPU切換線程時記錄當前線程的執行位置,以便下次繼續從當前位置往下執行。
直接內存
這塊不屬于JAVA虛擬機內存,但使用頻繁,也可稱之為“堆外內存”
Java虛擬機垃圾收集器
根據上述對JAVA虛擬機內存區域模型的介紹,我們知道JAVA程序中的對象實例都存儲在JAVA堆內存中,因此垃圾收集主要也是針對堆內存進行。為了更好的管理JAVA對象實例,并結合對象實例的生存時間長短,JAVA虛擬機將堆內存分為新生代和老年代,分別存儲剛創建不久的對象和存活較長時間的對象實例,并采用分代收集的策略分別回收新生代和老年代的內存。
內存分配與回收策略
1、 分代收集思路。根據JAVA對象的生存周期特點,虛擬機將堆內存分為新生代和老年代,并分別采用新生代和老年代的垃圾回收策略。
2、 新生代細分為Eden區和兩個Survivor區(即From區和To區)。大多數新生對象創建頻繁,且存活時間短,為了提高新生代區域垃圾收集效率,新創建的對象存放在Eden區,當Eden區快滿的時候,虛擬機對其觸發一次Minor GC,將新生代存活對象移動到From區,原來From區的對象根據存活年齡決定放到To區還是老年代,然后清空Eden區和From區,接著將To區對象全部移到From區。
3、 大對象直接進入老年代,可以配置新生代對象的最大值,對象超過這個值就直接進入老年代。
4、 發起Minor GC前,會先判斷老年代最大可用連續空間是否大于新生代對象占用的空間,如果小于或不允許冒險,則觸發一次Full GC。
垃圾收集算法(3種基本算法)
1、 復制算法。針對于新生代的垃圾收集算法。當新生代Eden區快滿的時候,將Eden區對象復制到From區,將From區對象根據存活年齡決定復制到To區還是到老年代,然后清除Eden區和From區,接著將To區對象復制到From區。
2、 標記-清除算法。垃圾收集算法標記出需要回收的對象,標記完成后直接統一回收。垃圾收集器使用可達性分析來判斷哪些對象是否存活,通過設置一系列GC Roots節點(包括棧、方法區中的靜態屬性和常量所引用的對象,以及本地方法棧中引用的對象),從這類節點往下搜索,當對象不在GC Root節點的引用鏈上時,說明對象不可達,可以被回收。
3、 標記-整理算法。垃圾收集算法標記出需要回收的對象,標記完成后將存活對象往內存的一端移動,然后直接清理掉端邊界以外的內存。
小編推薦一個學Java的學習裙【 七六零,二五零,五四一 】,無論你是大牛還是小白,是想轉行還是想入行都可以來了解一起進步一起學習!裙內有開發工具,很多干貨和技術資料分享!
常用垃圾收集器
由于虛擬機中的垃圾收集是分代收集的,新生代和老年代的垃圾收集策略不太一樣,所以一般是使用針對新生代和老年代的垃圾收集器組合。
1、 Serial GC。新生代收集器,采用復制算法,用于Client客戶端新生代垃圾收集,針對內存占用較少的應用進行垃圾收集。
2、 Serial Old GC。老年代收集器,采用標記-整理算法,用于Client客戶端老年代垃圾收集,針對內存占用較少的應用進行垃圾收集。
3、 Parallel Scavenge GC。新生代收集器,采用復制算法,并行收集新生代內存垃圾,可以設置垃圾收集器的吞吐量,還可以設置自動適配調節吞吐量。
4、 Parallel New GC。新生代收集器,采用復制算法,并行收集新生代內存垃圾。
5、 Parallel Old GC。老年代收集器,采用標記-整理算法,并行收集老年代內存垃圾。
6、 CMS GC。老年代收集器,采用標記-清除算法,并行收集老年代內存垃圾,不整理內存。由于在執行垃圾收集期間不中斷業務線程,所以容易產出“浮動垃圾”,導致Full GC。可以通過設置參數來觸發內存整理任務。
7、 G1 GC。不再將堆內存區分新生代和老年代,而是將堆內存看作若干個均分小區域,并對最空閑的內存區域進行標記和回收。適用于大內存的應用。
配置垃圾收集機器參數
1、UseSerialGC:虛擬機允許在Client模式下的默認值,打開此配置后,虛擬機使用Serial GC + Serial Old GC 的收集器組合進行內存回收。
2、UseParNewGc:使用ParNew + Serial Old 的收集器組合進行內存回收。
3、UseConcMarkSweepGC:使用ParNew + CMS + Serial Old GC的收集器組合進行內存回收。
4、UseParallelGC:虛擬機允許在Server模式下的默認值,使用Parallel Scavenge + Serial Old 的收集器組合進行內存回收。
5、UseParallelOldGC: 使用Parallel Scavenge + Parallel Old GC的收集器組合進行內存回收。
6、SuriviorRatio:新生代中Eden區域與Surivior區域的容量比值,默認是8:1。
7、PretenureSizeThreshold:設置這個值后,大于這個值的對象直接進入老年代。
8、MaxtenuringThreshold:對象年齡超過這個值時進入老年代。
9、ParallelGCThreads:設置并行GC時進行內存回收的線程數。
10、UseAdaptiveSizePolicy:動態調整堆內存中各個區域的大小和進入老年代的對象年齡。
11、HandlerPromotionFailure:是否允許分配擔保失敗。
12、GCTimeRatio:僅在Parallel ScaVenge收集器時生效,設置GC時間占總運行時間的比率,默認為1%。
13、MaxGCPauseMills:僅在Parallel ScaVenge收集器時生效,設置GC的最大停頓時間。
小編推薦一個學Java的學習裙【 七六零,二五零,五四一 】,無論你是大牛還是小白,是想轉行還是想入行都可以來了解一起進步一起學習!裙內有開發工具,很多干貨和技術資料分享!
14、CMSInitiatingOccupancyFraction:設置CMS收集器在老年代空間被使用多少后觸發垃圾收集,默認68%,在設置CMS收集器時生效。
15、UseCMSCompactAtFullCollection:在設置CMS收集器時生效,設置CMS收集器在完成垃圾收集后是否進行一次碎片整理。
16、CMSFullGCsBeforeCompaction:僅在使用CMS時生效,設置CMS收集器在進行若干次收集后再啟動一次內存碎片整理。