java
如今講究的是高併發,分佈式,高可用,充分壓榨機器的性能,機器性能最大化,良好的JVM調優就能夠增長電腦的負載算法
方法區:最重要的內存區域,多線程共享,保存了類的信息(名稱、成員、接口、父類),反射機制是其重要的組成部分,動態進行類操做的實現安全
堆內存(Heap):保存對象的真實信息,該內存牽扯到釋放問題(GC)服務器
棧內存(Stack) :線程的私有空間,在每一次進行方法調用的時候都會存在有棧幀,採用先進後出的設計原則多線程
本地變量表:局部參數或形參,容許保存有32位的插槽(Solt),若是超過了32位的產毒就須要開闢兩個連續性的插槽(long,double)Valatile關鍵字問題併發
操做數棧:執行全部的方法計算操做分佈式
常量池引用:String類實列,...高併發
返回地址:方法執行完畢後的恢復執行的點性能
程序計數器:執行指定的一個順序編碼,該區域的所佔比率幾乎能夠忽略優化
本地方法棧:與棧內存的功能相似,區別在因而爲本地方法服務的
合理的內存模型可使GC的性能更增強大,沒必要太大的浪費服務器的性能,從而減小阻塞所帶來的程序的性能影響
Java中數據保存的內存位置:堆內存(調優、原理)
最須要強調的就是jdk1.8以後所帶來的內存結果改變以及GC策略提高
jdk1.8:
當內存不足的時候就須要進行伸縮區的控制,當內存充足的時候就能夠考慮將伸縮區所佔用的內存釋放掉,若是伸縮區一直佔有這個區域,會形成其餘區域的內存相對少,確定會在成額外的計算性能的影響,致使程序的總體性能降低,若是咱們肯定咱們當前是高併發的訪問,而且咱們的程序是獨立在一臺服務器上,那麼這臺服務器的資源就應該所有給我使用,而不是給伸縮區留一大塊動態區域
伸縮區的看見 = MaxMemory - TotalMemory ( 特別大的一塊內存空間被閒置了起來 )
jdk1.8之前:
對象實列化須要依靠關鍵字new來完成,全部新對象都會在伊甸園區開闢,若是伊甸園區的內存空間不足,就會發生MiorGC
有些對象執行了後翅MinorGC後依然存在,伊甸園區的內存空間是有限的,那麼這些對象將進入到存活取(存活區有兩個,一個負責保存存活對象,一個負責晉升,對象只佔用一個空間,永遠都有一個空的)
若是經歷了若干次MinorGC回收處理以後發現看見依然不夠使用,那麼則進行老年代的GC回收,執行一個MajorGC(FUll GC 性能不好),若是能夠回收空間,則繼續進行MINorGC
若是MajorGC失敗,則內存已經被佔用完,拋出OOM異常
若是新建立的對象的空間佔用過大,會直接保存在老年代之中
【備註]】: jdk1.8默認會根據系統的不一樣二選擇不一樣的GC回收策略
jdk1.9-jdk11 使用的默認GC就是G1
引用計數:早期的JVM使用的方法,會儲存對象的全部引用數,會控制這個引用數的多少,在引用數爲0的時候,則 視爲能夠進行垃圾回收
對象引用遍歷:如今大部分JVM採用的方法,從一組對象開始,沿着該對象涉及到的對象造成一個樹 ( 本身理解 ),經過遞歸的方式,肯定可達對象,不可達對象就會被視爲再也不須要,將其進行標記做爲垃圾收集,釋放對應的內存,可是釋放的內存都是離散的,不是連續的,不足於裝載新的對象,不少GC會有優化操做,會從新組織內存中的對象,並進行壓縮,造成連續的內存空間供使用。
引用對象的強度:包裝了咱們實際須要的對象,使咱們能夠直接維護對引用對象的直接引用,能夠理解爲:給某個對象的引用進行了一層加強,使其擁有了其餘的狀態,咱們能夠根據他的狀態進行辨別,對象在沒有任何引用指向的時候纔會被看成垃圾回收,若是咱們想對有引用指向的對象作垃圾回收處理,這個時候就涉及到了引用對象的概念,引用對象的強度將決定垃圾回收器的行爲,注意:咱們普通使用的引用都是強度最大的引用,
【強可達、軟可達、弱可達、虛可達、不可達】,
對象的可達性狀態會觸發垃圾回收期做出相應的行爲:
軟可達對象可能會任憑垃圾回收器去回收;
弱可達對象將會被垃圾回收器回收;
爲了不程序的運行線程和GC的回收線程發生併發影響,JVM採用安全點機制來實現STW(Stop The World),也就是當垃圾收集線程發起了STW請求後,工做線程開始進行安全點檢查,只有大概全部線程都進入安全點之後,垃圾回收線程才能夠開始工做,在垃圾收集線程工做的過程當中,工做線程沒執行一行代碼都會進行安全點檢測,若是這行代碼安全就繼續執行,若是這行代碼不安全,就將所有線程掛起,這樣保證在垃圾回收線程的工做過程當中,工做線程也能夠繼續執行
安全點:列如阻塞線程確定是安全點,運行的jni線程若是不放問java對象也是安全的,若是線程在編譯生成機器碼那他也是安全的,Java虛擬機在有垃圾回收縣城執行期間,沒自信一個字節碼都會進行安全檢測
基礎垃圾收集算法:清除算法會形成垃圾碎片,清除後整理壓縮又浪費CPU且耗時,複製算法浪費內存可是很快
基礎假設:
大部分的Java對象都生命週期都很短暫,只有不多部分以對象能存活好久,新建的對象放到新生代,當通過屢次垃圾回收且還存在的對象,就將其移動到老年代,針對不一樣的區域採用不一樣的算法,因我新生代的對象存活週期很短,常常都須要垃圾回收,因此通常採用速度很快的複製算法,因此新生代分分紅兩塊,一塊eden區,兩塊大小相同的servivor區(用做於複製)
對象初期都在eden區分配空間,因爲堆的內存空間是共享的,因此分配內存須要加鎖且同步,否則會發生兩個對象引用指向用一塊內存的狀況發生,爲了不頻繁的加鎖,一個線程能夠申請一塊連續的內存空間,後續內存的分配就在這裏進行,這個訪問被稱爲Tlab,Tlab裏面維護了兩個指針,一個是當前空餘內存的起始位置,另外一個Tail指向尾巴申請的內存結束位置,分配內存的時候就只須要進行指針加法並判斷是否大於tail,若是超過則須要從新申請Tail,
當eden區滿了就會進行一次minorGC,將ende區存活的對象和form區的對象移動到to區,而後交換form和to的指針
年輕代回收算法:
"複製"清理算法,將保留的對象複製到存活區之中,存活區的內容會保存到老年代資中
伊甸園老是會有大量的新對象產生,全部HotSpot虛擬機使用了BTP(單一CPU的時候全部的兌現一次保存),TLAB(拆分 爲不一樣的塊,根據CPU的核心個數拆分),技術形式處理
老年代回收算法
"標記—清除"算法,想進行對象的第一次標記,在這段時間之內會暫停程序的執行(若是標記的時間廠或者對象的內容過多,這個暫停的時間就會很長,就會產生串行標記,並行標記等問題)
"標記—壓縮"算法,基於"標記—清除"算法,將零散的內存空間進行整理壓縮從新集合再分配
【年輕代】串行GC / 並行回收GC / 並行GC
【老年代】 串行GC / 並行GC / CMS
STW: [Stop—The—World]
暫時掛起全部的程序的執行線程,進行無用的對象標記
沒有任何意向合適的GC回收操做,從JDK1.8開始提供有G1收集器,在JDK11以後提供額ZGC
支持大內存(4G-64G),支持有多CPU,減小STW停頓時間,能夠保證併發狀態下程序的執行