1、深刻java虛擬機—JVM視頻課程java
深刻JVM(Java Virtual Machine)web
java內存模型面試
java內存模型概覽算法
在運行時數據區之中內存的分配一共有五個模塊:緩存
1、堆內存Heap:保存真正的程序的數據的部分。服務器
2、棧Stack:保存堆內存的地址、基本數據、方法的執行;數據結構
3、方法區:保存全部的方法的具體操做,該區域屬於共享;多線程
4、程序計數器:這是一塊很小的內存,小到幾乎能夠忽略的地步,只是作一個程序執行順序的記錄,只是爲了標記下一步要執行的代碼的順序號;併發
5、本地方法棧:該棧之中所保存的都是操做系統的原生函數;oracle
堆和方法區共享、棧、程序計數器、本地方法棧獨享
StackOverFlowError和OutOfMemoryError:
若是請求的棧的深度過大,虛擬機可能會拋出StackOverFlowError,
若是虛擬機的實現中容許虛擬機棧動態擴展,當內存不足以擴展棧的時候,會拋出OutOfMemoryError。
總結:
1、形成StackOverFlowError和OutOfMemoryError的緣由:
2、在JVM的棧內存中保存有棧幀的概念,全部的棧內存採用後進先出的數據結構進行存儲。
Java對象訪問模式:
JVM默認的運行模式:
1.HotSpot虛擬機採用了混合模式的模式來運行;
運行的形式使用的是server模式,該模式佔用內存大,啓動的速度慢,可是處理的效率最高。
第二章JVM內存模型與垃圾收集
JVM垃圾回收主要是指堆內存空間,那麼在每一次執行GC的時候須要區分那些內存須要回收那些不須要回收,因此爲了總體的回收處理方便,JVM將對內存分爲以下的幾個組成部分,須要考慮jdk的版本:
2.1java堆內存模型
新生代:那些剛剛建立的對象,剛剛建立的對象有可能會存在許多的垃圾對象,那麼這些對象應該是被優先回收的。
老年代:老不死的那類對象,通過了不少次清理以後,該對象依然有用;
永久代:intern()方法進入池的對象實際上就在永久代中,永久代不會被回收,由於至關於一個bug存在,因此在jdk1.8以後將其更換爲元空間(電腦的直接內存)。
2.2對象建立與垃圾回收流程
垃圾回收兩種形式:自動調用、手工調用(runtime.getRuntime().gc()
1、當程序之中須要產生新的實例化對象(反射實例化、new對象、clone對象),爲新的對象申請空間;
2、新對象要申請的對象空間默認都是在伊甸園區(新生)進行開闢,因此首先須要判斷伊甸園區是否有空餘的內存空間,若是有空餘的內存空間直接在伊甸園區開闢新的堆內存空間,此時不會發生有GC處理;
3、若是新對象沒法在伊甸園空間申請新的空間,那麼就表示如今的伊甸園區的內存空間不足,不足就須要將那些無用的新對象進行回收(Minor GC),當回收完成後要繼續判斷該空間是否還有空餘的空間容納下新的對象,若是能夠容納,則開闢新空間,保存新對象。
4、若是此時伊甸園區即便執行了Minor GC後依然發現沒有能夠回收的對象,那麼這個時候將判斷存活區是否有空間(存活區通常與伊甸區的比率1:1:8)若是存活區有空餘空間,則將這些活躍的伊甸區的部分對象直接保存給存活區,就至關於伊甸園區能夠騰出部分空間(這個空間很是小)來供新對象進行使用。
5、若是此時存活區依然滿了(空間不足),則繼續向老年代進行內存空間申請,若是老年代有空餘的空間則將存活區中的活躍對象保存在老年代,然後存活區獲得了空間釋放,伊甸園區也獲得了空間釋放,則對象空間申請成功。,
6、若是老年代也是滿的,那麼這個時候會執行FULL GC(徹底GC/Major GC)進行老年代的內存釋放,若是能夠釋放則進行對象的保存,若是釋放不成功則表示已經沒有可用的內存空間了,那麼就會拋出OOM異常。
*GC的觸發條件:Minor GC、FULL GC(Major GC)
Minor GC:發生在年輕代內存空間,當年輕代內存空間不足時會進行觸發,釋放年輕代中不活躍對象。
Major GC:發生在老年代內存空間,當老年代的空間不足時會自動觸發Full GC,若是觸發以後,內存空間依然不足,則會產生OOM錯誤提示。
2.3java堆內存調整參數
GC雖然能夠進行內存空間的釋放,但頻繁的GC確定會影響系統性能,那麼如何才能夠不頻繁的發生GC呢?內存越大GC發生的頻率就越低,系統的性能就越高。
JAVA內存調整策略(內存優化策略)
若是取消掉伸縮區的概念,讓初始化的內存就是最大的可用內存空間,這樣就能夠實現JVM的性能調整避免了重複的內存的控制操做,可讓整個的代碼的執行速度上升。-Xms -Xmx
面試題:如何對JVM進行調優:
1、在堆內存之中存在一個伸縮區的概念,默認狀況下最大可用內存爲總體內存的四分之一,默認使用的內存爲總體內存的六十四分之一,這個時候只須要避免伸縮區的頻繁變動,就能夠提高程序的性能
2、能夠在程序執行的時候-Xms設置初始化內存, -Xmx設置最大可用內存、將這兩個內容設置爲同樣空間大小,就能夠提高JVM的運行性能。
2、4年輕代
年輕代:年輕代主要分爲兩個區域:伊甸區、存活區
全部新建立的對象都會存活在伊甸區,可是伊甸區的保存的空間必定是最大的,畢竟產生新對象的概率是很高的,在伊甸園區裏面因爲對象常常可能只是臨時建立,因此其擁有一個Minor GC的操做處理,而通過屢次的Minor GC後依然被保留下來的對象,就應該認爲該對象不該該被回收,則將此對象保存到存活區中。
存活區分爲兩類:主要負責對象的晉級,向老年代晉級。而且這兩個存活區有一塊是專門進行對象回收的,因此有一塊內存空間老是空的。因爲伊甸園區保存的對象數據較多,因此默認的比率爲8:1:1.
年輕代GC實現算法-複製算法Copying
算法:複製採用的方式爲從根集合掃描出存活的對象,並將找到的存活對象複製到一塊新的徹底未使用的空間中。
在通過GC以前必定會先發生一次全對象的掃描處理操做,經過掃描才能夠知道哪些對象是垃圾空間。
年輕代優化算法:
在實際運行中,因爲Eden區老是會保存大量的新生對象,因此HotSpot虛擬機爲了能夠加快此空間的內存分配,而使用了Bump-The-Pointer和TLAB(Thread-Local-Allocation-Buffers)兩種技術。
BTP算法(記錄棧中最後一個對象後面的剩餘空間)能夠提升內存的分配速度,但並不適合多線程的操做狀況。
TLAB算法將伊甸園區分爲多個數據塊,每一個數據塊分別使用BTP技術進行對象保存於內存分配。
在java內存中,全部的堆內存是線程共享的區域。
年輕代內存調整參數:
-Mmn 設置年輕代堆內存大小,默認爲物理內存的1/64.
-Xss設置每一個線程棧的大小,JDK1.5以後默認爲每一個線程分配1M的棧大小,減小此數值能夠產生更多的線程對象,可是不能無限生成。
-XX:SurvivorRatio設置伊甸區與存活區空間的大小比例8:1:1,不建議修改。
2、5老年代調整
老年代空間的主要目的是用於存儲由Eden區發送過來的對象,通常經歷過好幾回Minor GC還會保存下來的對象,纔會被複制到老年代,通常老年代的內存空間大小會設置的比年輕代大,這樣能夠存放更多的對象,同時在老年代中執行GC的次數也相對較少,當老年代內存不足時會自動執行Full GC。
算法:標記-清除(Mark-Sweep)採用的方式爲從根集合開始掃描,對存活區的對象進行標記,標記完畢後、再掃描整個空間中未標記的對象,並進行回收。
優缺點:在空間中存活對象較多的狀況下較爲高效,但因爲該算法爲直接回收不存活對象所佔用的內存,所以會形成內存碎片。
算法:標記-壓縮Mark-Compact
標記階段與標記清除算法相同,可是在清除階段有所不一樣。在回收不存活對象所佔用的內存空間後,會將其餘全部存活對象都往左端的空間進行移動,並更新引用其對象指針。
優缺點:在標記-清除Mark-Compact的基礎上還須要進行對象移動,成本相對高,好處則是不產生內存碎片。
-XX:PretenureSizeTnreshold控制直接進入老年代的對象大小,大於這個值的對象會直接分配在老年代中,不通過年輕代。
2.6 永久代(JDK1.8被廢除)
Jdk1.8以前的一個bug性的存在,其核心的本質在於:該區域中的對象不會被回收。方法區就是永久代。HotSpot虛擬機中存在有永久代的概念,可是BEA和IBM的虛擬機是不包含永久代概念的,oracle將hotspot永久代取消了。
2.7元空間(永久代的替代品)MetaSpace的本質是本機的物理內存,其做用和永久代相同,可是元空間和永久代最大的區別,元空間用的是物理內存(受到本機的物理內存的限制),而永久代是JVM的內存空間,自己受到JVM的限制。
-XX:MetaspaceSize 設置元空間的初始大小
-XX:MaxMetaspaceSize設置元空間的最大內存默認沒有限制,受到本機物理內存限制
面試題:請問是否知道什麼叫OOM?怎麼會出現?
OutOfMemoryError指的是內存溢出問題,內存的溢出須要考慮如下幾種狀況:
java堆內存溢出Java heap space:每每出如今Full GC失敗以後。
永久代PermGen space:一個方法中出現的內存溢出。
元空間MetaSpace:分配的物理內存不足,或者數據量高於物理內存。
第三章 垃圾收集策略
JVM會本身選擇合適的垃圾收集策略,而用戶也能夠本身來設置本身所須要的垃圾收集策略,可是就我的而言採用默認的垃圾收集處理策略。
垃圾的收集必定要分兩個空間考慮:年輕代、老年代。
老年代的內存空間》年輕代的內存空間,因此老年代的對象每一次執行GC都會消耗更多的時間。
可用GC方式:
新生代可用GC策略:
串行GC(Serial Copying)
並行回收GC(Parallel Scavenge)
並行GC(ParNew)
老年代可用GC策略:
串行GC(Serial MSC)
並行huishouGC(Parallel MSC)
併發GC(CMS)
同一種垃圾的收集策略,有可能會根據觸發內存代的不一樣有不一樣的效果,因此先來看各個內存的操做特色。
新生代—串行GC
算法:複製Copy
過程:掃描出新生代中存活的對象;
Minor GC將存活的對象複製到作爲To Sapce的S0/S1區;
以前作爲To Space/From Space的S0/S1區對換角色;
經歷過幾回Minor GC任然存活的對象,放入老年代。
年輕代並行GC Parallel Scavenge
算法:負責Copying清理算法;
操做步驟:在掃描和複製時均採用多線程方式處理,並行回收GC爲空間較大的年輕代回收提供許多優化。
優點:在多CPU的機器上其GC耗時會比串行方式短,適合多CPU、對暫停時間的要求較短的應用。
也就是說一個GC的處理操做,須要有多個線程共同完成,一個線程負責內存的掃描(掃描出全部不用的內存對象,)而另一個線程負責對象的複製操做。
並行回收只是處理年輕代的,而並行GC須要與老年代的GC結合。
年輕代並行GC(ParNew)
算法:複製Copying清理算法
操做步驟:並行GC必須結合老年代」CMS GC」一塊兒使用。由於在年輕代若是發生了「Minor GC」時,老年代也須要使用「CMS GC」 同時處理(並行回收GC並不會作這些)。
CMS(Concurrent Mark-Sweep)是以犧牲吞吐量爲代價來得到最短回收停頓時間的垃圾回收器。對於要求服務器響應速度的應用上,這種垃圾回收器很是適合。
老年代串行GC(Serial MSC)
算法:標記-清除-壓縮(Mark-Sweep-Compact)
操做步驟:
掃描老年代中還存活的對象,而且對這些對象進行標記;
遍歷整個老年代內存空間,回收全部未標記的對象內存;
將全部存活對象都集中在一端,然後將全部回收的對象的內存空間變爲一塊連續的內存空間。
優缺點:串行執行的過程當中爲單線程,須要暫停應用並耗時較長。
全部的串行GC處理都只是單線程處理,那麼在進行處理的時候都必須暫停操做。
老年代並行GC(Parallel Mark Sweep 、Parallel Compacting)
算法:標記-壓縮(Mark-Compact)
操做步驟:
將老年代內存空間按照線程個數劃分爲若干個子區域;
多個線程並行對各自的子區域內的存活對象進行標記;
多個線程並行清除全部未標記的對象;
多個線程並行將多個存活對象整理在一塊兒,並將全部被回收的對象空間整合爲一體。
優缺點:多個線程同時進行垃圾回收能夠縮短應用暫停的時間,可是因爲老年代的空間通常較大,因此在掃描和標記存活對象上須要花費較長時間。
老年代並行GC (Concurrent Mark-Sweep GC、CMS GC)
算法:標記-清除(Mark-Sweep)
操做步驟:
初始標記(STWInitial Mark):虛擬機暫停正在執行的任務(STW),由根對象掃描出全部的關聯對象,並作標記。此過程只會致使短暫的JVM暫停。
併發標記:(Concurrent Marking)恢復全部暫停的線程對象,而且對以前標記過的對象進行掃描,取得全部跟標記對象有關聯的對象。
併發預清理(Concurrent Precleaning):查找全部在併發標記階段新進入老年代的對象(一些對象可能重新生代晉升到老年代,或者有一些對象被分配到老年代),經過從新掃描,減小下一階段的工做。
從新標記(STW Remark):此階段會暫停JVM,對在」併發標記「階段被改變引用或新建立的對象進行標記;
併發清理(Concurrent Sweeping):恢復全部的暫停的應用線程,對全部未標記的垃圾對象進行清理,而且會盡可能將已回收的對象的空間從新拼湊爲一個總體。在此階段收集器線程和應用程序線程併發執行。
併發重置(Concurrent Reset):重置CMS收集器的數據結構,等待下一次垃圾回收。
優缺點:只有在第一次和從新標記階段纔會暫停整個應用,這樣對應用程序所帶來的影響很是小。缺點是併發標記與回收線程會與應用線程爭搶CPU資源,而且容易產生內存碎片。
第四章 G1收集器
G1收集器簡介:
G1收集器Garbage ·First是從JDK1.7u4版本以後正式引入到java中的垃圾收集器,此類垃圾收集器主要應用在多CPU以及大內存的服務器環境下,這樣能夠極大的減小垃圾收集的停頓時間,以提高服務器的操做性能。引入此收集器的主要目的是爲了未來的某一時間內能夠替換掉CMS收集器。
G1的實現方案至關於如今將全部的子內存區域合併在一塊兒,也不進行任何的區分,這樣就至關於全部的內存的區域均可以按照統一的方式規劃處理。而G1最大的特色就是避免了全內存掃描。
G1的回收策略:
在整個G1進行標記和清理的時候是按照區域完成的,這樣不影響其餘區域的執行,除此以外,適用的形式和以前的CMS都是很是相似的操做方式。
G1相關處理參數:
若是要使用G1收集器,則必須有用戶本身來進行參數指定,有以下的可用參數,
第五章 Java引用類型
引用類型概述:
強引用(Strong Reference):即便進行了屢次的GC回收,即便JVM的內存不夠用了,即便JVM最終不得已拋出了OOM錯誤,那麼該引用繼續搶佔。
軟引用(Soft Reference):當內存空間不足時,能夠回收此內存空間;若是充足則不回收。通常能夠用在緩存處理操做開發;
弱引用(Weak Reference):無論內存是否夠用,只要一出現GC處理,則當即回收。
幽靈引用(Phantom Reference):和沒有引用是同樣的。
軟引用與強引用區別:
軟引用中保存的內存若是在內存富裕的時候會繼續保留,內存不足會做爲第一批的丟棄者進行垃圾空間的釋放。在開發中能夠利用軟引用實現高速緩存組件。
引用隊列:
引用對象裏面保存的就是一個要準備被回收的對象對的信息。
幽靈引用直接把要保存的內容保存在了引用隊列之中了。