Java面試必備——JVM篇

1. Java的內存模型以及GC算法java

1、Java內存模型算法

Java 虛擬機具備一個堆,堆是運行時數據區域,全部類實例和數組的內存均今後處分配sql

JVM主要管理兩種類型內存:堆和非堆,堆內存(Heap Memory)是在 Java 虛擬機啓動時建立,非堆內存(Non-heap Memory)是在JVM堆以外的內存數組

簡單來講,堆是Java代碼可及的內存,留給開發人員使用的;非堆是JVM留給本身用的,包含方法區、JVM內部處理或優化所需的內存(如 JITCompiler,Just-in-time Compiler,即時編譯後的代碼緩存)、每一個類結構(如運行時常數池、字段和方法數據)以及方法和構造方法的代碼緩存

JVM 內存包含以下幾個部分:服務器

堆內存(Heap Memory): 存放Java對象網絡

非堆內存(Non-Heap Memory): 存放類加載信息和其它meta-data架構

其它(Other): 存放JVM 自身代碼等併發

Method Area 和 Heap 是線程共享的jvm

JVM初始運行的時候都會分配好 Method Area(方法區) 和Heap(堆),而JVM 每遇到一個線程,就爲其分配一個 Program Counter Register(程序計數器) , VM Stack(虛擬機棧)和Native Method Stack (本地方法棧), 當線程終止時,三者(虛擬機棧,本地方法棧和程序計數器)所佔用的內存空間也會被釋放掉。

2、Java內存分配

Java的內存管理實際上就是變量和對象的管理,其中包括對象的分配和釋放。

JVM內存申請過程以下:

JVM 會試圖爲相關Java對象在Eden中初始化一塊內存區域

當Eden空間足夠時,內存申請結束;不然到下一步

JVM 試圖釋放在Eden中全部不活躍的對象(這屬於1或更高級的垃圾回收),釋放後若Eden空間仍然不足以放入新對象,則試圖將部分Eden中活躍對象放入Survivor區

Survivor區被用來做爲Eden及OLD的中間交換區域,當OLD區空間足夠時,Survivor區的對象會被移到Old區,不然會被保留在Survivor區

當OLD區空間不夠時,JVM 會在OLD區進行徹底的垃圾收集(0級)

徹底垃圾收集後,若Survivor及OLD區仍然沒法存放從Eden複製過來的部分對象,致使JVM沒法在Eden區爲新對象建立內存區域,則出現」out of memory」錯誤

4、GC分代劃分

爲了進行高效的垃圾回收,虛擬機把堆內存劃分紅新生代(Young Generation)、老年代(Old Generation)和永久代(Permanent Generation)3個區域。

1) 在Young Generation中,有一個叫Eden Space的空間,主要是用來存放新生的對象,還有兩個Survivor Spaces(from、to),它們的大小老是同樣,它們用來存放每次垃圾回收後存活下來的對象

2) 在Old Generation中,主要存放應用程序中生命週期長的內存對象

3) 在Young Generation塊中,垃圾回收通常用Copying的算法,速度快。每次GC的時候,存活下來的對象首先由Eden拷貝到某個SurvivorSpace,當Survivor Space空間滿了後,剩下的live對象就被直接拷貝到OldGeneration中去。所以,每次GC後,Eden內存塊會被清空。

4) 在Old Generation塊中,垃圾回收通常用mark-compact的算法,速度慢些,但減小內存要求

5) 垃圾回收分多級,0級爲所有(Full)的垃圾回收,會回收OLD段中的垃圾;1級或以上爲部分垃圾回收,只會回收Young中的垃圾,內存溢出一般發生於OLD段或Perm段垃圾回收後,仍然無內存空間容納新的Java對象的狀況

2. jvm性能調優都作了什麼

JVM啓動參數:調整各代的內存比例和垃圾回收算法,提升吞吐量

目標:

GC的時間足夠的小

GC的次數足夠的少

發生Full GC的週期足夠的長

實踐:

(1)針對JVM堆的設置,通常能夠經過-Xms -Xmx限定其最小、最大值,爲了防止垃圾收集器在最小、最大之間收縮堆而產生額外的時間,咱們一般把最大、最小設置爲相同的值

(2)年輕代和年老代將根據默認的比例(1:2)分配堆內存,能夠經過調整兩者之間的比率NewRadio來調整兩者之間的大小,也能夠針對回收代,好比年輕代,經過 -XX:newSize -XX:MaxNewSize來設置其絕對大小。一樣,爲了防止年輕代的堆收縮,咱們一般會把-XX:newSize -XX:MaxNewSize設置爲一樣大小

(3)年輕代和年老代設置多大才算合理?這個我問題毫無疑問是沒有答案的,不然也就不會有調優。咱們觀察一下兩者大小變化有哪些影響

更大的年輕代必然致使更小的年老代,大的年輕代會延長普通GC的週期,但會增長每次GC的時間;小的年老代會致使更頻繁的Full GC

更小的年輕代必然致使更大年老代,小的年輕代會致使普通GC很頻繁,但每次的GC時間會更短;大的年老代會減小Full GC的頻率

如何選擇應該依賴應用程序對象生命週期的分佈狀況:若是應用存在大量的臨時對象,應該選擇更大的年輕代;若是存在相對較多的持久對象,年老代應該適當增大。但不少應用都沒有這樣明顯的特性,在抉擇時應該根據如下兩點:(A)本着Full GC儘可能少的原則,讓年老代儘可能緩存經常使用對象,JVM的默認比例1:2也是這個道理 (B)經過觀察應用一段時間,看其餘在峯值時年老代會佔多少內存,在不影響Full GC的前提下,根據實際狀況加大年輕代,好比能夠把比例控制在1:1。但應該給年老代至少預留1/3的增加空間

(4)在配置較好的機器上(好比多核、大內存),能夠爲年老代選擇並行收集算法: -XX:+UseParallelOldGC ,默認爲Serial收集

(5)線程堆棧的設置:每一個線程默認會開啓1M的堆棧,用於存放棧幀、調用參數、局部變量等,對大多數應用而言這個默認值太了,通常256K就足用。理論上,在內存不變的狀況下,減小每一個線程的堆棧,能夠產生更多的線程,但這實際上還受限於操做系統。

程序算法:改進程序邏輯算法提升性能

調優原則:

一、多數的Java應用不須要在服務器上進行GC優化;

二、多數致使GC問題的Java應用,都不是由於咱們參數設置錯誤,而是代碼問題;

三、在應用上線以前,先考慮將機器的JVM參數設置到最優(最適合);

四、減小建立對象的數量;

五、減小使用全局變量和大對象;

六、GC優化是到最後不得已才採用的手段;

七、在實際使用中,分析GC狀況優化代碼比優化GC參數要多得多;

調優目的:

一、將轉移到老年代的對象數量下降到最小;

二、減小full GC的執行時間;

調優手段:

一、減小使用全局變量和大對象;

二、調整新生代的大小到最合適;

三、設置老年代的大小爲最合適;

四、選擇合適的GC收集器;

調優步驟:

1,監控GC的狀態

2,分析結果,判斷是否須要優化

若是各項參數設置合理,系統沒有超時日誌出現,GC頻率不高,GC耗時不高,那麼沒有必要進行GC優化;若是GC時間超過1-3秒,或者頻繁GC,則必須優化;

注:若是知足下面的指標,則通常不須要進行GC:

Minor GC執行時間不到50ms;

Minor GC執行不頻繁,約10秒一次;

Full GC執行時間不到1s;

Full GC執行頻率不算頻繁,不低於10分鐘1次;

3,調整GC類型和內存分配

4,不斷的分析和調整

5,全面應用參數

3. 介紹JVM中7個區域,而後把每一個區域可能形成內存的溢出的狀況說明

順口溜:器池堆,棧棧區區;棄池堆,站站曲曲(一離開衛生間,肚子疼的站不起身)

虛擬機規範中的7個內存區域分別是三個線程私有的和四個線程共享的內存區

線程私有內存區域:與線程具備相同生命週期,分別是:指令計數器、線程棧和本地線程棧

四個共享區:是全部線程共享的,在JVM啓動時就會分配,分別是:方法區、 常量池、直接內存區和堆(即咱們一般所說的JVM的內存分爲堆和棧中的堆,後者就是前面的線程棧)

4. jvm 如何分配直接內存,常量池解析

直接內存:並非虛擬機運行時數據區的一部分,但直接內存被頻繁使用也可能致使OutOfMemoryError異常出現。在NIO中,引入了一種基於通道和緩衝區的I/O方式,它可使用native函數直接分配堆外內存,而後經過一個存儲在java堆中的DirectByteBuffer對象做爲這塊內存的引用進行操做

-XX:MaxDirectMemorySize設置最大值,默認與java堆最大值同樣

常量池:JVM爲每一個已加載的類型維護一個常量池,常量池就是這個類型用到的常量的一個有序集合。包括直接常量(基本類型,String)和對其餘類型、方法、字段的符號引用。池中的數據和數組同樣經過索引訪問。因爲常量池包含了一個類型全部的對其餘類型、方法、字段的符號引用,因此常量池在Java的動態連接中起了核心做用。常量池存在於堆中

5. 數組多大放在JVM老年代

虛擬機提供了一個-XX:PretenureSizeThreshold參數,令大於這個設置值的對象直接在老年代中分配。這樣作的目的是避免在Eden區及兩個Survivor區之間發生大量的內存拷貝

新生代經歷minor gc ,年齡到達閾值。過大對象。minor gc後仍存在大量對象,分配survivor不能存儲的對象到老年代。某種相同年齡對象相加綜合大於survivor一半,大於或等於這個年齡值的對象直接到老年代

對應的年輕代回收機制是:標記-複製。(圖片來自網絡)

對應的老年代回收機制是:標記-清除(或標記-整理)。(圖片來自網絡)

1. 標記-清除

2. 標記-複製

3. 標記-整理

4. 分代回收

Java架構資料分享,獲取方式請到架構圈圈:948368769 領取(有高可用、高併發、高性能及分佈式、Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)

相關文章
相關標籤/搜索