這是一篇看了能說的出來的jvm面試;我的能力有限,文中描述不免有錯誤,請指正;html
jvm會將運行程序所管理的空間分爲若干部分,每一個部分都起到相當重要的部分;jdk1.8java運行時數據區以下:java
程序計數器
:當前線程執行字節碼的行號指示器;字節碼解析器經過改變計數器的值,來選取下一條須要執行的字節碼指令,分支、循環、跳轉、異常處理、線程恢復等基礎功能;面試
Java 虛擬機棧
: java方法執行的內存模型,每一個方法被執行的時候都會建立幀棧用於存儲局部變量表、操做數棧、動態連接、方法出口等信息;算法
本地方法棧
: 執行java的native方法服務,每一個方法被執行的時候都會建立幀棧用於存儲局部變量表、操做數棧、動態連接、方法出口等信息;數組
Java 堆
: 儲存對象的實例和數組;安全
方法區
: 非堆,儲存類的結構信息;例如運行時常量池的字段和方法數據,構造函數和普通方法的字節碼內容等;併發
科普運行時經常使用池:運行時經常使用池是class文件中每個類或者接口的常量池表的運行表現形式,包括若干種常量,如字段和方法的引用;在類加載至虛擬機的時候就會建立運行時常量池;科普幀棧:幀棧用於儲存數據和部分過程結果的數據,同時也會處理動態連接,方法返回值和分派;幀棧隨着方法的建立而建立,隨着方法的銷燬而銷燬;幀棧中維護着本地變量表,操做數棧,和指向當前方法所屬類的運行常量池的引用;oracle
注意:jdk1.8已經使用元空間替代了jdk1.7方法區中的永久代,元空間存在於native內存中,其大小根據本地內存而定,沒有限制;詳細看官網地址jvm
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/considerations.html#sthref66socket
類的加載過程分爲 加載,連接,初始化,使用,和卸載5個階段,其中鏈接階段又分爲驗證 準備和解析階段;
內存溢出:申請了8個字節的空間,可是你在這個空間寫入9或以上字節的數據,出現內存溢出;
在java內存模型中只有程序計數器不會發生OOM(out of memory),其他地區都會發生OOM;
當一個類收到了類加載請求時,本身不會先去加載這個類,而是將其委派給父類去加載,若是父類不能加載,反饋給子類,由子類去完成類的加載;
這邊有可能會問,你都知道哪些類加載器:
如何打破雙親委派模型?
雙親委派模型都依靠loadClass()
,重寫loaderClass()
便可;
新生代分爲 3 個分區:Eden(伊甸園)、Survivor一、Survivor2;其中Survivor一、 Survivor2 合起來成爲Survivor(倖存區); 若是沒有Survivor,Eden區每進行一次Minor GC
,存活的對象都會被送到老年代。老年代將很快被填滿,老年代每發生一次Full GC
的速度比 Minor GC
慢10倍;
Survivor 的做用就是減小老年代Full GC
的次數,至關於緩衝帶;Eden和Survivor的比例分配8:1;
官網:
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/generations.html#sthref16
會出現的小問題就是:Minor GC和Full GC觸發條件,答默認狀況下發生15次Minor GC以後就會觸發一次Full GC
GC 是垃圾收集(GabageCollection);Java 提供的 GC 功能能夠自動監測對象是否超過做用域從而達到自動回收內存的目的,而不須要人爲手動釋放內存;主要調用的是 System.gc() 和 Runtime.getRuntime().gc();
CMS(Concurrent Mark Sweep)收集器基於標記—清除算法
實現的收集器,是一種以獲取最短回收停頓時間爲目標的收集器。主要優勢是併發收集,低停頓,在cpu多核的狀況下性能較好。在啓動 JVM 的參數加上
「-XX:+UseConcMarkSweepGC」來指定使用 CMS 垃圾回收器;其使用在老年代 能夠配合新生代的Serial和ParNew收集器一塊兒使用;因爲 CMS 使用 標記—清除算法
GC時會產生大量碎片,有可能提早觸發Full GC;若是在老年代充滿以前沒法回收不可達對象,或者沒有足夠的空間知足分配就會致使Concurrent Mode Failure(併發模式故障);
官網:
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/cms.html
G1(Garbage-First)從總體來看是基於標記—整理
算法實現的收集器,可以實現併發並行,對cpu利用率較高,減小停頓時間。目標是取代jdk1.5發佈的CMS收集器。G1收集器收集範圍是老年代和新生代
,不須要結合其餘收集器使用,G1收集器可預測垃圾回收的停頓時間,對空間進行整合;因爲G1是基於複製算法實現,當沒有足夠的空間(region)分配存活的對象就會致使Allocation (Evacuation) Failure(分配失敗);
官網:
官網:
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/collectors.html#sthref27
Java中Stop-The-World機制簡稱STW,是在執行垃圾收集算法時,Java應用程序的其餘全部線程都被掛起。Stop-The-World對系統性能存在影響,所以垃圾回收的一個原則是儘可能減小「Stop-The-World」的時間;
標記-清除法
:標記出沒有用的對象,以後一個一個回收掉
複製算法
: 按照容量劃分二個大小相等的內存區域,當一塊用完的時候將活着的對象複製到另外一塊上,而後再把已使用的內存空間一次清理掉
標記-整理法
:標記出沒有用的對象,讓全部存活的對象都向一端移動,而後直接清除掉端邊界之外的對象
分代回收
:根據對象存活週期的不一樣將內存劃分爲幾塊,通常是新生代和老年代,新生代基本採用複製算法,老年代採用標記整理算法
內存泄漏:new申請了一塊內存,後來很長時間都再也不使用了(按理應該釋放),可是由於一直被某個或某些實例所持有致使 GC 不能回收;
經典案例
void test(){
Vector vector = new Vector();
for (int i = 1; i<100; i++)
{
Object object = new Object();
vector.add(object);
object = null;
}
//...對vector的操做
//...與vector無關的其餘操做
}
手動解決賦值null便可
void test(){
Vector vector = new Vector();
for (int i = 1; i<100; i++)
{
Object object = new Object();
vector.add(object);
object = null;
}
//...對vector的操做
vector = null;
//...與vector無關的其餘操做
}
還有各類流和socket的close方法未被調用也會發生內存泄漏問題;
不會,在下一個垃圾回收週期中回收對象。
若是你對文中的知識點不太理解 推薦閱讀周志明先生《深刻理解Java虛擬機:JVM高級特性與最佳實踐(第3版)》和做者給出的官網連接!!!!
求關注吖