
一、內存模型
1.一、堆
- 堆是全部線程共享的,主要存放對象實例和數組。
- 新生代和老年代的比例是1:2。
- 新生代中三個區域的比例是 8 : 1 : 1。
1.1.一、新生代
對象分配在eden區中,當eden區滿時會觸發minor gc,將eden區中存活的對象,複製到survivor0區中,清空eden區,當survivor0中滿了時,會將存活的對象複製到survivor1區中,而後將survivor0和survivor1交換,保持survivor1是空的。每通過一次yong gc 年齡就+1。java
對象建立,對象分配在eden區,當eden區滿了,再建立對象的時候,會觸發minor gc,進行Eden和from surivior區域的垃圾回收。算法
minor gc後還存活的對象會被放入此區域,當對象年齡到達閾值後會進入老年代。或者to surivior區域滿了,會將對象放入老年代。數組
1.1.二、老年代
- 大對象,須要大量連續內存空間的對象
- 長期存活的對象,對象年齡超過15(默認值)
- yong gc後survivor區容不下的對象。
1.二、JVM棧
線程私有的,每一個線程都有一個棧,主要存放當前線程的局部變量,程序運行狀態,方法返回值,方法出口等。緩存
1.三、本地方法棧
爲虛擬機使用到的native方法服務。併發
1.四、方法區
用於存放已經被夾在的類信息,常量,靜態變量,1.8後取消了永久代,增長了元空間,元空間並不在虛擬機中,而是用的是本地內存。元空間中存放類的元信息,靜態變量和常量池移入堆中。app
1.五、程序計數器
- 程序私有,生命週期與程序相同
- 當前線程所執行的字節碼的行號指示器。
- 用來實現分支,循環,跳轉,異常等功能。
二、常量池中包括什麼
常量池在編譯時期肯定,存放在編譯生成的class文件中,包含了基本數據類型和對象類型(String和數組)jvm
三、如何判斷對象是否存活
使用什麼方法標記一個對象可回收?xss
- 引用計數法,每一個對象都有一個引用計數器,被引用+1 當引用數爲0即爲可被GC的對象
- 可達性分析:從根節點出發,向下搜索,未訪問到的對象標記爲不可達,可被回收
四、哪些對象能夠用爲GC ROOT對象
- 虛擬機棧中引用的對象。
- 方法區中靜態對象引用的對象。
- 方法區中常量引用的對象。
- 本地方法棧中引用的對象。
五、GC策略
- 標記清除法,從根節點進行掃描,對存活的對象進行標記,標記完成後,再掃描整個空間中未被標記的對象,進行清理。容易形成內存碎片
- 複製,將內存劃分爲兩份,當其中一分內存滿了時,從根節點掃描,將存活的對象複製到另外一分內存中。不會出現內存碎片問題,但須要兩倍的空間。
- 標記整理,如標記清除法同樣,標記對象,清除後將全部存活對象向左移。避免了內存碎片和兩倍空間的問題,但增長了移動對象的成本。
六、具體GC收集器
- 串行垃圾收集器,serial
- 並行垃圾收集器 parNew,parallel 注重吞吐量
- cms 注重最短回收停頓時間
- G1
cms和G1的區別 :工具
- cms是新生代的垃圾收集器,採用標記清除。
- G1是新生代和老年代的垃圾收集器,採用標記整理。
- cms會產生內存碎片,G1並不會。
- Cms追求最小停頓時間,G1是達到可控的停頓時間,儘量提升吞吐量。
七、什麼樣的對象進入老年代
- 大對象,須要大量連續內存空間的對象。
- 長期存活的對象,對象年齡超過15(默認值)。
- yong Gc後survivor區容不下的對象。
八、爲何要區分新生代和老年代
- 對象的生存狀況不一樣使用不一樣的GC算法。
- 新生代對象可能被頻繁的建立和回收,老年代回收較少。
九、survivor區存在的意義
- 爲了提升對象進入老年代的門檻,減小fullGC的次數,由於fullGC很耗時。
- 兩個survivor的做用是爲了減小survivor區的內存碎片。
十、什麼是yangGC
對年輕代進行gc。觸發條件:性能
-
eden區不足
- 清空eden from to中沒被引用的對象。
- 將eden from中存活的對象 複製到 to中。
- 將to中的對象晉升到old中,包括兩類對象,一個是年齡到達閾值,一個是to中放不下。
- full gc也會出發yong gc
十一、何時觸發fullGC
- 手動觸發的GC。
- 老年代的空間不足。
- 永久代的空間滿了(方法區)。
- 統計到yong gc晉升到老年代的平均大小大於老年代剩餘的大小(老年代的空間不足)。
- jvm自身固定頻率的fullGC(默認一小時執行一次)。
十二、內存的配置參數
- xms xmx 配置堆內存的最小和最大值
- xmn 年輕代內存的初始大小
- xss jvm棧大小
1三、對象分配內存的兩種方式
- 指針碰撞,若是內存對象是規整的,採用指針碰撞來爲對象分配內存,全部使用過的內存在指針的一側,未使用過的內存在指針的另外一側,分配內存只須要移動指針便可。
- 空閒列表,內存不規整,使用過的內存和未使用過的內存交織在一塊兒,維護一個內存使用列表,記錄那些內存是可用的,在分配的時候找到一塊足夠大的空間劃分給對象,並更新列表上的內容。
1四、如何減小GC的開銷
- 避免顯示的調用System.gc。
- 儘可能減小臨時對象的使用。
- 對象不使用時,最好顯式的置爲null。
- 儘可能使用StringBuffer而不用String累加字符串。
- 能用基本類型就是用基本類型。
- 儘可能少用靜態對象變量。
1五、什麼是JAVA內存模型(JMM)
用於屏蔽掉各類硬件和操做系統的內存訪問差別,以實現讓java程序在各個平臺下都能達到一致的併發效果。
1六、什麼時happens-before
- 保證了內存的可見性
-
制定了四個規則:
- 程序順序規則:一個線程中的每一個操做 happens-before 與後續的全部操做。
- 監視器鎖規則:一個監視器解鎖 happens-before 於 加鎖。
- volatile變量規則: 寫操做 happens-before 讀操做。
- 傳遞性 A happens-before B ,B happens-before C ,那麼Ahappens-before C。
1七、性能調優工具
17.一、jps
jps主要用來輸出jvm中運行的進程狀態信息。
-l 輸出main類或者jar的權限名。
17.二、jstack
jstack pid > log
能夠將線程堆棧轉存到文件中。
日誌分析可使用fastthread.io。
17.三、jstat
能夠顯示出虛擬機進程中的classloader、內存、gc等運行數據。
參數
-class pid 類加載統計。
-gc 垃圾回收統計 ,後面跟兩個參數一個是間隔輸出時間,一個是總共輸出次數。
gc日誌可使用 gceasy.io
17.四、jmap
jmap查看堆內存的使用狀況:
jmap pid
17.五、jinfo
查看java程序的運行環境參數:
jinfo pid
1八、內存柵欄
經過確保從另外一個CPU來看,屏障的兩邊的全部指令都是正確的程序順序,而保持程序順序的外部可見性;其次能夠實現內存數據可見性,確保內存數據會同步到CPU緩存子系統。
1九、JVM產生的內存溢出及解決辦法
- java heap space
代碼中存在大對象的分配,屢次GC後仍找不到分配空間。
解決辦法:查看是否有大對象分配尤爲是大數組。經過jmap把堆內存的日誌dump下來,分析日誌,若是解決不了增長堆內存的空間。
- permspace metaspace
永久代或元空間溢出。生成大量的代理類或者使用自定義的類加載器。
解決辦法:查看有沒有配置永久代或者元空間的大小。是否長時間沒有重啓jvm,是否有大量的反射操做。
