JVM基礎篇

一、基礎術語
	1.1 進程和線程
		進程:計算機內部每個正在系統上運行的程序都是一個進程,每個進程包含一個到多個線程
		線程:線程是程序中一個單一的順序控制流程,在單個程序中同時運行多個線程完成不同的工作稱爲多線程
	1.2 內存泄漏(Memory Leak):
			用動態存儲分配函數動態開闢的空間,在使用完畢後未被釋放,結果導致一直佔據內存單元,一直持續到程序結束,常見的異
		常OutOfMemory
	1.3 強引用(Strong Reference):
			在一個線程內,無需引用直接可以使用的對象,除非引用不存在,否則強引用不會被GC清理,變量
		的聲明就是強引用,String str = new String("str")
	1.4 軟引用(Soft Reference):
			JVM拋出OOM異常之前,GC會清理所有軟引用對象。垃圾回收器在某個時刻決定回收軟可達的對象的時
		候,會清理軟引用,Java虛擬機會盡量讓軟引用存活的時間長一點,迫不得已在清理
	1.5 弱引用(Weak Reference):
			弱引用對象與軟引用對象最大的不用在於,當GC在進行回收時,需要通過算法檢查是否回收軟引用,
		而對於弱引用總是進行回收。
	1.6 虛引用(Phantom Reference):
			又稱爲幽靈引用,主要的目的是在一個對象所佔的內存被實際回收之前得到通知,從而可以進行一
		些相關的清理工作。虛引用在創建時必須提供一個引用隊列作爲參數,其次虛引用對象的get方法總是返回null。
	1.7 finalization機制:
			finalization機制允許開發人員提供對象銷燬之前的自定義處理邏輯。Object類提供了finalize方法添加用戶自定義銷燬
		邏輯,如果一個類有特殊的銷燬邏輯,可以覆寫finalize方法
	1.8 Interned Strings
			String 類型的常量池,直接使用雙引號和使用String提供的intern()方法的字符串會放入常量池
	1.9 並行與併發
			*並行是指兩個或者多個事件在同一時刻發生,而併發是指兩個或多個事件在同一時間間隔發生
			*並行是在不同實體上的多個事件,併發實在同一實體上的多個事件
			*並行是在一臺處理器上”同時“處理多個任務,併發是在多臺處理器上同時處理多個任務,如hadoop集羣
	1.10根集合與堆棧
			*棧是運行時的單位,而堆是存儲的單位
			*棧解決程序運行的問題,即程序如何執行,或者說如何處理數據。堆解決的是數據存儲的問題,及數據怎麼放、放到哪
	1.11 回收算法
		標記-清除(Make-Sweep)算法:首先標記除存活的對象,那些沒有被標記的就可以被收集了
		複製(Copying)算法:將內存分爲兩個部分,收集的時候,存活的對象從一部分移動到另一部分
		標記-整理(Mark-Compact)算法:結合了標記-清除與複製兩個算法的優點,分爲兩個階段,第一階段從根節點開始標記所有被
									引用的對象,地二個階段遍歷整個堆,清除未標記對象並把存活對象”壓縮“到堆的其中一塊,
									按順序排放
		分代收集(Generational Collecting)算法:java使用的算法
	1.12 年輕代(Young Generation)
			年輕代分爲三部分一個Eden兩個Servivor,默認比例爲8:1,當GC發生在年輕代對象的行爲稱爲Minor GC。
	1.13 老年代(Old Generation)
			當GC發生在老年代時稱爲Major GC 或者 Full GC 
	1.14 對象提升(Promotion)規則
			如果對象在Eden出生並經過一次Minor GC 後仍然存活,並且能被Servivor容納的話,將被移動到Survivor空間中,並將對象的年齡加1.
		對象在Survivor區中每熬過一次Minor GC 年齡就增加1歲,當對象的年齡增加到一定程度(默認15歲)時,就會被提升到老年代中。
	1.15 Full GC 
		除了調用System.gc外,觸發Full GC 執行的情況有如下四種
		*老年代空間不足:老年代空間只有在年輕代對象轉入及創建爲大對象、大數組時纔會出現不足的現象,當執行Full GC後,空間仍然不足
						則會報Java.lang.OutOfMemoryError:PermGen space
		*永久代空間滿
		*CMS GC 時出現PromotionFailed 和 Goncurrent Mode Failure
		*統計得到Minor GC 晉升到老年代的平均大小大於老年代的剩餘空間
	1.16 Stop the World (STW)
			GC 時系統會進入的停頓的狀態
	1.17 對象存活判斷
			引用計數法:每個對象有一個引用計數屬性,新增一個引用時計數加1,引用釋放時計數減1,計數爲0時,可以回收。有循環引用的問題
			可達性分析(Reachability Analysis):從GC Roots 開始向下搜索,搜索所有走過的路徑,稱爲引用鏈。當一個對象到GC Roots沒有
												任何引用鏈相連時,則證明此對象是不可達對象。
	1.18 堆外內存(off-heap Memory)
			JVM內部會把所有的內存分爲Java使用的堆內存和Native是用的內存,他們之間是不能共享的。Native內存用完時,如果Java堆有空閒
		的內存,這是Native會重新向JVM申請,而不是直接使用Java堆內存。
			線程棧、應用程序代碼、NIO緩存用的都是對外內存。
	1.19 markOop
			markOop描述了一個對象(也包括了Class)的狀態信息,Java語法層面的每個對象或者Class在JVM的結構表示中都會包含一個markOop
		作爲Header,當然還有一些其他的JVM數據結構也用它做Header。markOop由32位或者64位構成。
			markOop的值根據所描述的對象的類型以及作用的不同而不同。就算在一個對象裏,他的值也是可能會不斷變化的,比如鎖對象,在
		一開始創建的時候其實不知道是鎖對象,會當成一個正常的對象來創建,在是隨着執行到synchronized的代理邏輯時,就知道其實是一個
		鎖對象了,他的值就改變了,該值是對應棧幀結構裏的監控對象列表裏的某一個地址。
	
	1.2 Java虛擬機內存模型
		Java虛擬機將其內存數據分爲程序計數器、虛擬機棧、本地方法棧、Java堆、方法區
		*程序計數器:用於存放下一條運行的命令
		*虛擬機棧、本地方法棧:用於存放函數調用堆棧信息
		*java堆:用於存放Java程序運行時所需的對象等數據
		*方法區:用於存放程序的類元數據信息
	1.3 程序計數器
			每個線程都需要有一個獨立的程序計數器,個個線程之間互不影響,它是線程私有的,所以生命週期與線程一致
	1.4 虛擬機棧
			JVM的架構是基於棧的,即程序指令的每一個操作都要經過入棧和出棧這樣的組合型操作才能完成。棧的優勢是訪問速度比堆塊
		,它僅次於寄存器。虛擬機棧主要存放一些基本類型的變量,int、short、long、byte、float、double、boolen
		、char、及對象的引用。Java虛擬機允許Java棧的大小是動態的或者固定不變的。在Java虛擬機中定義了兩種異常與棧有關,即
		StackoverFlowError和OutOfMemoryError,如果線程在計算過程中,請求的棧深度大於最大可用棧的深度,則程序運行過程中會
		拋出StackoverFlowError異常。在擴展棧的過程中沒有足夠的內存空間來支持棧的發展,則拋出OutOfMemoryError異常。
	1.5 本地方法棧(Native Method Stacks)
			本地方法棧和Java虛擬機棧的功能很相似,Java虛擬機棧用於管理Java函數的調用,而本地方法棧用於管理本地方法的調用。
		本地方法不是用Java實現的,而是使用c實現的。
	1.6 堆
			堆在JVM規範裏是一種通用性的內存池(也存在與RAM中),用於存放所有的Java對象。堆是一個運行時數據區,類的對象從中分配空間
		,這些對象通過New關鍵字創建,不需要程序代碼顯示的釋放。堆是由垃圾回收負責的,堆的優勢是可以動態地分配內存大小,生產週期
		也不需要事先告訴編譯器。由於它是運行時動態分配內存的,Java的垃圾收集器會自動收走那些不再使用的數據。但缺點是,由於要在運行
		時動態分配內存,所以數據訪問的速度較慢。大多數的虛擬機裏,Java中的對象和數組都存放在堆中
			堆不同於棧的優勢是,虛擬機不需要知道從堆內存要分配多少內存區域,也不必知道存儲的數據在堆內存活的時間有多長。因此,在
		堆內分配存儲相對於棧來說,有較大的靈活性。
			Java堆區在JVM啓動的是否被創建,它只要求邏輯上是連續的,在物理空間上可以不連續。所有線程共享Java堆。
	1.7 方法區 
			方法去主要保存的信息是類的元數據。被所有線程共享。
			*類型信息:類的完整名稱、父類的完整名稱、類型修飾符、類型的直接接口、類表
			*常量池:這個類方法域等信息所引用的常量信息。
			*域信息:域名稱、域類型、域修飾符
			*方法信息:方法名稱、返回類型、方法參數、方法修飾符、方法字節碼、操作數棧和方法棧的局部變量區大小以及異常表
			在HotSpot虛擬機中,方法區也被稱爲永久代,是一塊獨立於Java堆的內存空間。
			GC針對永久區的回收,通常主要從兩個方面分析:一是CG對永久區常量池的回收,二是永久區對類元數據的回收。
			HotSpot虛擬機對常量池的回收策略是明確的,只要 常量池中的常量沒有被任何地方引用,就可以回收。
	1.8 引用計數法(垃圾標記算法)
			在GC執行垃圾回收之前,首先要區分出內存中哪些是存活對象,哪些是已經死亡對象,CG纔會在執行垃圾回收時,釋放掉其所佔用的
		內存空間,因此這個過程我們可以稱爲垃圾標記階段。對於一個對象A,只要任何一個對象引用了A,則A的引用計數器就加1,當引用失效
		時,引用計數器就減1。只要對象A的引用計數器的值爲0,則對象A就不可能在被使用。引用計數法無法處理循環引用的問題。
	1.9 根搜索算法(垃圾標記算法)
			HotSpot和大部分JVM都是使用根搜索算法作爲垃圾標記的算法。根搜索算法是以根對象集合爲起始點,按照從上至下的方式搜索被根
		對象集合所連接的目標是否可達(使用根搜索算法後,內存中的存活對象都會被根對象集合直接或間接連接着),如果目標對象不可達,就
		意味着該對象已經死亡。根對象集合中包含了5個元素,Java棧內的對象引用、本地方法棧內對象的引用、運行常量池中的對象引用、方法
		區中對象的引用、方法區中類靜態屬性的對象引用以及一個類對應唯一數據類型的Class對象。
	1.10 分代收集算法(Generational Collecting)(垃圾回收算法)
			它將所有的新建對象都放入稱爲年輕代的內存區域,年輕代的特點是對象會很快回收,因此,在年輕代就選擇效率教高的複製算法。
		當一個對象經過幾次回收後依然存活,對象就會被放入稱爲老年代的內存空間。老年代使用的標記-壓縮算法提高垃圾回收效率。
		
		
	2.1 GC概念
			CG(Garbage Collection)就是JVM中自動內存管理機制的具體實現。在HotSpot中,GCd的工作任務主要劃分爲兩部分,內存的動態分配
		和垃圾回收。在內存執行分配之前,GC首先會對內存空間進行劃分。JVM堆如果還要進一步劃分的話,還可以劃分爲年輕代(YoungGen)和
		老年代(OldGen),其中年輕代又可以劃分爲Eden空間、From Survivor空間和To Survivor空間。
	2.2 Serial收集器	
			Serial收集器默認爲HotSpot中Client模式下的年輕代垃圾收集器(適合在單核下使用)
	2.3 ParNew 收集器
			是Serial收集器的多線程版本。
	2.4 Parallel收集器
			和ParNew收集器不同,Parallel收集器可以控制程序的吞吐量大小,和STW的時間間隔。HotSpot的年輕代中除了擁有ParNew收集器
		是基於並行回收的以外,Parallel收集器同樣採用了複製算法、並行回收和STW機制。和ParNew收集器不同的是,Parallel收集器可以
		控制程序的吞吐量大小,因此它也被稱爲吞吐量優先的垃圾收集器。在程序開發中,開發人員可以通過選項-XX:GCTimeRatio設置執行
		回收的時間所佔比例,也就是控制GC的執行頻率,默認值爲99,也就是說,將有1%的時間用來執行垃圾回收,還提供選擇
		-XX:MaxGCPauseMills設置執行內存回收時STW的暫停時間閥值,如果指定了改選項,Parallel收集器將會儘可能地在設定時間範圍內
		完成回收。
			Parallel收集器也提供用於執行老年代垃圾收集的Parallel Old收集器,Parallel Old採用標記-壓縮算法,但同樣也是基於並行
		回收和STW機制。在程序吞吐量優先的場景中,Parallel收集器和Parallel Old收集器的組合,在Server模式下的回收性能不錯。在
		程序開發過程中,可以通過選項-XX:UseParallelGC手動指定Parallel收集器執行內存回收的任務。使用選項-XX:UseAdaptiveSizePolicy
		可以打開自適應GC策略,在這種模式下,年輕大的大小、Eden和servivor的比例、晉升老年代對象年齡等參數會被自動調整,以達到
		在堆大小、吞吐量和停頓時間之間的平衡點,在手動調優比較困難的場合,可以直接使用這種自適應的方式,僅指定虛擬機的最大堆、
		目標的吞吐量(GCTimeRatio)和停頓時間(MaxGCPauseMills),讓虛擬機自己完成調優工作。
	2.5 CMS 收集器
			CMS天生爲併發而生,低延遲是他的優勢,不過垃圾收集算法沒有采用標記-複製算法,而是採用標記-清除算法。CMS包括四個階段,
		初始階段、併發階段、再標記階段、併發消除階段。
			CMS收集器的回收週期以一個稱爲初始標記的階段開始,在這個階段中,程序中所有的工作線程都會因爲Stop-the-Word機制出現短暫
		的暫停,這個階段主要的任務就是標記出內存中那些被根對象集合所連接的目標對象是否可達,一旦標記完成之後就會恢復之前被暫停的
		所有應用程序線程。接下來將會進入併發標記階段,而這個階段的主要任務就是將之前的不可達的對象標記爲垃圾對象。在CMS最終執行
		回收之前,儘管看上去這些垃圾對象都已經被成功標記了,但是由於在併發標記階段中,程序的工作線程和垃圾收集線程同時運行,或者
		交叉運行,因此併發標記階段無法有效確保之前標記爲垃圾的無用對象的引用關係遭到更改,爲你解決這個問題,CMS會進入到再次標記
		階段,這樣一來,程序會因爲Stop-the-World機制再次出現短暫的暫停,以確保這些垃圾對象能夠成功且正確的標記。
			CMS收集器提供選項-XX:UseCmsCompactAtFullCollection,用於指定執行完Full GC之後是否對內存空間進行壓縮整理
			CMS收集器提供選項-XX:CMSFullGCCsBeforeCompaction用於設置執行了對少次Full GC後對內存進行壓縮整理
			CMS收集器提供選項-XX:CMSInitiatingOccupanyFraction,用於設置當老年代中的內存使用率達到多少百分比的時候執行內存回收,默認92
			CMS收集器不會等到堆內存飽和時才進行垃圾回收,而是當堆內存使用率達到某一閥值時,便開始進行回收,以確保應用程序在CMS工作過程
		中依然有足夠的空間支持應用程序運行。如果應用程序的內存使用率增長很快,在CMS的執行過程中,已經出現了內存不足的情況,此時
		CMS會回收失敗,JVM將啓動老年代串行收集器進行垃圾回收,如果這樣,程序將完全中斷。
	2.6 Garbage First(G1) GC 
			G1GC切分堆內存爲對個區間(Region),從而避免了很多GC操作在整個Java堆或者整個年代進行。在JVM啓動時不需立即指定哪些Region屬於
		年輕代,哪些Region屬於老年代,因爲無論年輕代或老年代,他們都不需要一大塊連續的內存塊,只是有一系列的Region組成而已。
			G1的年輕代收集階段是一個並行的獨佔收集器。和其他HotSpot垃圾收集器一樣,當一個年輕代收集進行時,整個年輕代會被回收,
		所有應該程序線程會中斷,G1 GC會啓用多線程執行年輕代回收。和年輕代不同,老年代的G1回收器和其他HotSpot不同,G1的老年代回收期
		不需要整個老年代被回收,一次只需要掃描/回收一小部分老年代的Region就可以了。這個老年代的Region和年輕代一起被回收。
			G1的最大貢獻是它可以讓我們設置最大停頓時間,只要設置了這個時間,G1就會通過自動調整年輕代空間大小和整體Java堆空間大小
		來匹配這個目標停頓時間。比如你設置了一個很短的停頓時間,G1會設置比較小的年輕代、比較大的整個Java堆空間,對應的老年代也會比較大
		總得來說,G1和CMS的目標是構建針對大內存回收的較短停頓時間,如果想要提高應用的內部吞吐量,也可以忍受較長的停頓時間,那麼還是
		選擇Parallel GC吧,畢竟他是專門爲了高吞吐量而研發的。
	
		
	3.1 -XX:PrintGCDetails
			該選項用於記錄GC運行時的詳細數據信息並輸出
	3.2 -Xloggc
			以文件形式保存GC日誌  -Xloggc:gc.log
	3.3 -XX:+PrintGCApplicationStoppedTime
			輸出GC造成的應用程序暫停間隔。一般和-XX:+PrintGCApplicationConcurrentTime一起使用。
	3.4 -XX:ConcGCThreads
			用來設置用於執行GC線程的數量
	3.5	-XX:G1HeapRegionSize
			G1GC用來設置Region的大小1M到32M之間
	3.6	-XX:G1HeapWastePercent
			這個選項控制G1GC不回收的空閒內存比例,默認是堆內存的5% 
		
		
		
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章