首頁>技術>

1.什麼是JVM?

JVM 的全稱是 「Java Virtual Machine」,也就是我們耳熟能詳的 Java 虛擬機器。它能識別 .class字尾的檔案,並且能夠解析它的指令,最終呼叫作業系統上的函式,完成我們想要的操作。

C++開發出來的程式,編譯成二進位制檔案後,就可以直接執行了,作業系統是能夠識別的。

但是咱們的Java程式就不一樣了,使用javac命令編譯出來的的.class檔案之後,作業系統是不能識別的,需要對應JVM去做一個轉換後,作業系統才能識別。

2.說說JDK、JRE、JVM的關係?

JDK是Sun公司(已被Oracle收購)針對Java開發員的軟體開發工具包。自從Java推出以來,JDK已經成為使用最廣泛的Java SDK(Software development kit)。

JRE全稱Java Runtime Environment,是執行基於Java語言編寫的程式所不可缺少的執行環境。也是透過它,Java的開發者才得以將自己開發的程式釋出到使用者手中,讓使用者使用。

JVM 就是 Java 虛擬機器,它能識別 .class字尾的檔案,並且能夠解析它的指令,最終呼叫作業系統上的函式,完成我們想要的操作。

JDK中包含JRE,也包括JDK,而JRE也包括JDK。

範圍關係:JDK>JRE>JVM。

3.獲取class檔案有哪些方式?從本地檔案系統中載入.class檔案從jar包中或者war包中載入.class檔案透過網路或者從資料庫中載入.class檔案把一個Java原始檔動態編譯,並載入,載入進來後就,系統為這個.class檔案生成一個對應的Class物件。4.生成Class物件的有哪些方式?

1.物件獲取。呼叫person類的父類方法getClaass();

2.類名獲取。每個型別(包括基本型別和引用)都有一個靜態屬性,class;

3.Class類的靜態方法獲取。forName("字串的類名")寫全名,要帶包名。(包名.類名)

5.類載入器有哪些?Bootstrap ClassLoader

負責載入$JAVA_HOME中 jre/lib/rt.jar裡所有的class或Xbootclassoath選項指定的jar包。由C++實現,不是ClassLoader子類。

Extension ClassLoader

負責載入Java平臺中擴充套件功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或 -Djava.ext.dirs指定目錄下的jar包。

App ClassLoader

負責載入classpath中指定的jar包及 Djava.class.path所指定目錄下的類和jar包。

Custom ClassLoader

透過java.lang.ClassLoader的子類自定義載入class,屬於應用程式根據自身需要自定義的ClassLoader,如tomcat、jboss都會根據j2ee規範自行實現ClassLoader。

6.如何自定義類載入器?

使用者根據需求自己定義的。需要繼承自ClassLoader,重寫方法findClass()。

如果想要編寫自己的類載入器,只需要兩步:

繼承ClassLoader類覆蓋findClass(String className)方法

**ClassLoader**超類的loadClass方法用於將類的載入操作委託給其父類載入器去進行,只有當該類尚未載入並且父類載入器也無法載入該類時,才呼叫findClass方法。如果要實現該方法,必須做到以下幾點:

7.如何設定Java虛擬機器棧的大小呢?

可以使用虛擬機器引數-Xss 選項來設定執行緒的最大棧空間,棧的大小直接決定了函式呼叫的最大可達深度;

-Xss size

8.方法區、堆、棧之間到底有什麼關係?棧指向堆

如果在棧幀中有一個變數,型別為引用型別,比如

package com.tian.my_code.test;public class JvmCodeDemo {    public  Object testGC(){        int op1 = 10;        int op2 = 3;        Object obj = new Object();        Object result=obj;        return result;    }}

這時候就是典型的棧中元素obj指向堆中的Object物件,result的指向和obj的指向為同一個物件。

使用命令

javac -g:vars JvmCodeDemo.java

進行編譯,然後再使用

javap -v JvmCodeDemo.class >log.txt

然後開啟log.txt檔案

方法區指向堆

方法區中會存放靜態變數,常量等資料。

如果是下面這種情況,就是典型的方法區中元素指向堆中的物件。【「紅線」

堆指向方法區

方法區中會包含類的資訊,物件儲存在堆中,建立一個物件的前提是有對應的類資訊,這個類資訊就在方法區中。

9.Java物件記憶體是如何佈局的?

一個Java物件在記憶體中包括3個部分:物件頭、例項資料和對齊填充。

10.如何理解Minor/Major/Full GC?

還可能問你:請說一下Minor/Major/Full GC分別傳送在哪個區域。

Minor GC:發生在年輕代的 GC Major GC:發生在老年代的 GC。Full GC:新生代+老年代,比如 Metaspace 區引起年輕代和老年代的回收。

11.能夠觸發條件 Full GC 有哪些?

1)呼叫System.gc時,系統建議執行Full GC,但是不必然執行;

2)老年代空間不足;

3)方法去空間不足;

4)透過Minor GC後進入老年代的平均大小 > 老年代的可用記憶體;

5)由Eden區、From Space區向To Space區複製時,物件大小大於To Space可用記憶體,則把該物件轉存到老年代,且老年代的可用記憶體小於該物件大小。即老年代無法存放下新年代過度到老年代的物件的時候,會觸發Full GC。

12.為什麼需要Survivor區?

如果沒有Survivor,Eden區每進行一次Minor GC ,並且沒有年齡限制的話, 存活的物件就會被送到老年代。這樣一來,老年代很快被填滿,觸發Major GC(因為Major GC一般伴隨著Minor GC,也可以看做觸發了Full GC)。老年代的記憶體空間遠大於新生代,進行一次Full GC消耗的時間比Minor GC長得多。

執行時間長有什麼壞處?頻發的Full GC消耗的時間很長,會影響大型程式的執行和響應速度。

可能你會說,那就對老年代的空間進行增加或者較少咯。

假如增加老年代空間,更多存活物件才能填滿老年代。雖然降低Full GC頻率,但是隨著老年代空間加大,一旦發生Full GC,執行所需要的時間更長。

假如減少老年代空間,雖然Full GC所需時間減少,但是老年代很快被存活物件填滿,Full GC頻率增加。

所以Survivor的存在意義,就是減少被送到老年代的物件,進而減少Full GC的發生,Survivor的預篩選保證,只有經歷16 次Minor GC還能在新生代中存活的物件,才會被送到老年代。

13.為什麼需要兩個大小一樣的Survivor區?

最大的好處就是解決了碎片化。

假設現在只有一個Survivor區,我們來模擬一下流程:

剛剛新建的物件在Eden中,一旦Eden滿了,觸發一次Minor GC,Eden中的存活物件就會被移動到Survivor區。這樣繼續循 環下去,下一次Eden滿了的時候,問題來了,此時進行Minor GC,Eden和Survivor各有一些存活物件,如果此時把Eden區的 存活物件硬放到Survivor區,很明顯這兩部分物件所佔有的記憶體是不連續的,也就導致了記憶體碎片化。

永遠有一個Survivor space是空的,另一個非空的Survivor space無碎片。

14.新生代中Eden:S1:S2為什麼是8:1:1?

新生代中的可用記憶體:複製演算法用來擔保的記憶體為9:1,所以只會造成 10% 的空間浪費。可用記憶體中Eden:S1區為8:1 即新生代中Eden:S1:S2 = 8:1:1

這個比例,是由引數 -XX:SurvivorRatio 進行配置的(預設為 8)。

15.如何判斷物件已死?引用計數法

給物件新增一個引用計數器,每當一個地方引用它object時計數加1,引用失去以後就減1,計數為0說明不再引用

優點:實現簡單,判定效率高缺點:無法解決物件相互迴圈引用的問題,物件A中引用了物件B,物件B中引用物件A。
public class A {    public B b; }public class B {    public C c; }public class C {    public A a; }public class Test{        private void test(){        A a = new A();        B b = new B();        C c = new C();                a.b=b;        b.c=c;        c.a=a;    }}
可達性分析演算法

當一個物件到GC Roots沒有引用鏈相連,即就是GC Roots到這個物件不可達時,證明物件不可用。

GC Roots種類:

Java 執行緒中,當前所有正在被呼叫的方法的引用型別引數、區域性變數、臨時值等。也就是與我們棧幀相關的各種引用。所有當前被載入的 Java 類。Java 類的引用型別靜態變數。執行時常量池裡的引用型別常量(String 或 Class 型別)。JVM 內部資料結構的一些引用,比如 sun.jvm.hotspot.memory.Universe 類。用於同步的監控物件,比如呼叫了物件的 wait() 方法。

public class Test{    private void test(C c){        A a = new A();        B b = new B();        a.b=b;        //這裡的a/b/c都是GC Root;    }}
16.物件的有幾種引用型別?強引用:User user=new User();我們開發中使用最多的物件引用方式。特點:我們平常典型編碼Object obj = new Object()中的obj就是強引用。透過關鍵字new建立的物件所關聯的引用就是強引用。當JVM記憶體空間不足,JVM寧願丟擲OutOfMemoryError執行時錯誤(OOM),使程式異常終止,也不會靠隨意回收具有強引用的“存活”物件來解決記憶體不足的問題。對於一個普通的物件,如果沒有其他的引用關係,只要超過了引用的作用域或者顯式地將相應(強)引用賦值為 null,就是可以被垃圾收集的了,具體回收時機還是要看垃圾收集策略。軟引用:SoftReference<Object> object=new SoftReference<Object>(new Object());特點:軟引用透過SoftReference類實現。軟引用的生命週期比強引用短一些。只有當 JVM 認為記憶體不足時,才會去試圖回收軟引用指向的物件:即JVM 會確保在丟擲 OutOfMemoryError 之前,清理軟引用指向的物件。軟引用可以和一個引用佇列(ReferenceQueue)聯合使用,如果軟引用所引用的物件被垃圾回收器回收,Java虛擬機器就會把這個軟引用加入到與之關聯的引用佇列中。後續,我們可以呼叫ReferenceQueue的poll()方法來檢查是否有它所關心的物件被回收。如果佇列為空,將返回一個null,否則該方法返回佇列中前面的一個Reference物件。應用場景:軟引用通常用來實現記憶體敏感的快取。如果還有空閒記憶體,就可以暫時保留快取,當記憶體不足時清理掉,這樣就保證了使用快取的同時,不會耗盡記憶體弱引用:WeakReference<Object> object=new WeakReference<Object> (new Object();ThreadLocal中有使用.弱引用透過WeakReference類實現。弱引用的生命週期比軟引用短。在垃圾回收器執行緒掃描它所管轄的記憶體區域的過程中,一旦發現了具有弱引用的物件,不管當前記憶體空間足夠與否,都會回收它的記憶體。由於垃圾回收器是一個優先順序很低的執行緒,因此不一定會很快回收弱引用的物件。弱引用可以和一個引用佇列(ReferenceQueue)聯合使用,如果弱引用所引用的物件被垃圾回收,Java虛擬機器就會把這個弱引用加入到與之關聯的引用佇列中。應用場景:弱應用同樣可用於記憶體敏感的快取。虛引用:幾乎沒見過使用, ReferenceQueue 、PhantomReference17.finalize方法有了解嗎?

這個方法就有點類似:某個人被判了死刑,但是不一定會死。

即使在可達性分析演算法中不可達的物件,也並非一定是“非死不可”的,這時候他們暫時處於“緩刑”階段,真正宣告一個物件死亡至少要經歷兩個階段:

1、如果物件在可達性分析演算法中不可達,那麼它會被第一次標記並進行一次篩選,刷選的條件是是否需要執行finalize()方法(當物件沒有覆蓋finalize()或者finalize()方法已經執行過了(物件的此方法只會執行一次)),虛擬機器將這兩種情況都會視為沒有必要執行)。

2、如果這個物件有必要執行finalize()方法會將其放入F-Queue佇列中,稍後GC將對F-Queue佇列進行第二次標記,如果在重寫finalize()方法中將物件自己賦值給某個類變數或者物件的成員變數,那麼第二次標記時候就會將它移出“即將回收”的集合。

18.垃圾回收演算法有哪些?標記-清除演算法

第一步:就是找出活躍的物件。我們反覆強調 GC 過程是逆向的, 根據 GC Roots 遍歷所有的可達物件,這個過程,就叫作標記。

第二步:除了上面標記出來的物件以外,其餘的都清楚掉。

缺點:標記和清除效率不高,標記和清除之後會產生大量不連續的記憶體碎片複製演算法

新生代使用,新生代分中Eden:S0:S1= 8:1:1,其中後面的1:1就是用來複制的。

當其中一塊記憶體使用完了,就將還存活的物件複製到另外一塊上面,然後把已經使用過的記憶體空間一次 清除掉。

一般物件分配都是進入新生代的eden區,如果Minor GC還存活則進入S0區,S0和S1不斷物件進行復制。物件存活年齡最大預設是15,大物件進來可能因為新生代不存在連續空間,所以會直接接入老年代。任何使用都有新生代的10%是空著的。

缺點:物件存活率高時,複製效率會較低,浪費記憶體。標記整理演算法

它的主要思路,就是移動所有存活的物件,且按照記憶體地址順序依次排列,然後將末端記憶體地址以後的記憶體全部回收。 但是需要注意,這只是一個理想狀態。物件的引用關係一般都是非常複雜的,我們這裡不對具體的演算法進行描述。我們只需要瞭解,從效率上來說,一般整理演算法是要低於複製演算法的。這個演算法是規避了記憶體碎片和記憶體浪費。

讓所有存活的物件都向一端移動,然後直接清理掉端邊界以外的記憶體。

從上面的三個演算法來看,其實沒有絕對最好的回收演算法,只有最適合的演算法。

19.新生代有哪些垃圾收集器?serial

Serial收集器是最基本、發展歷史最悠久的收集器,曾經(在JDK1.3.1之前)是虛擬機器新生代收集的唯一選擇。

它是一種單執行緒收集器,不僅僅意味著它只會使用一個CPU或者一條收集執行緒去完成垃圾收集工作,更重要的是其在進行垃圾收集的時候需要暫停其他執行緒。

優點:簡單高效,擁有很高的單執行緒收集效率 缺點:收集過程需要暫停所有執行緒 演算法:複製演算法 應用:Client模式下的預設新生代收集器

收集過程:

ParNew

可以把這個收集器理解為Serial收集器的多執行緒版本。

優點:在多CPU時,比Serial效率高。缺點:收集過程暫停所有應用程式執行緒,但CPU時比Serial效率差。演算法:複製演算法 應用:執行在Server模式下的虛擬機器中首選的新生代收集器

收集過程:

Parallel Scanvenge

Parallel Scavenge收集器是一個新生代收集器,它也是使用複製演算法的收集器,又是並行的多執行緒收集 器,看上去和ParNew一樣,但是Parallel Scanvenge更關注 系統的吞吐量 ;

吞吐量 = 執行使用者程式碼的時間 / (執行使用者程式碼的時間 + 垃圾收集時間)

比如虛擬機器總共運行了120秒,垃圾收集時間用了1秒,吞吐量=(120-1)/120=99.167%。

若吞吐量越大,意味著垃圾收集的時間越短,則使用者程式碼可以充分利用CPU資源,儘快完成程式的運算任務。

可設定引數:

-XX:MaxGCPauseMillis控制最大的垃圾收集停頓時間,-XX:GC Time Ratio直接設定吞吐量的大小。
20.老年代有哪些垃圾收集器?CMS=Concurrent Mark Sweep

「特點」:最短回收停頓時間,

「回收演算法」:標記-清除

「回收步驟」

初始標記:標記GC Roots直接關聯的物件,速度快併發標記:GC Roots Tracing過程,耗時長,與使用者程序併發工作重新標記:修正併發標記期間使用者程序執行而產生變化的標記,好似比初始標記長,但是遠遠小於併發標記表發清除:清除標記的物件

「缺點」:對CPU資源非常敏感,CPU少於4個時,CMS對使用者程式的影響可能變得很大,有此虛擬機器提供了“增量式併發收集器”;無法回收浮動垃圾;採用標記清除演算法會產生記憶體碎片,不過可以透過引數開啟記憶體碎片的合併整理。

收集過程:

serial old

Serial Old收集器是Serial收集器的老年代版本,也是一個單執行緒收集器,不同的是採用"標記-整理算 法",執行過程和Serial收集器一樣。

「適用場景」:JDK1.5前與Parallel Scanvenge配合使用,作為CMS的後備預案;

收集過程:

Parallel old

Parallel Old收集器是Parallel Scavenge收集器的老年代版本,使用多執行緒和"標記-整理演算法"進行垃圾 回收,吞吐量優先;

「回收演算法」:標記-整理

「適用場景」:為了替代serial old與Parallel Scanvenge配合使用

收集過程:

G1=Garbage first

從 JDK 9 開始,JVM 的預設垃圾回收器就從 Parallel GC 調整為 G1,並且開始全面廢除 CMS 。

限制或者減少 GC 停頓時間相比系統吞吐量而言更加重要,從 PGC 切換至低延遲的 G1 能夠為大部分使用者帶來更好的體驗。G1 的效能在 JDK 8 以及後續的 release 版本都得到了極大的最佳化,G1 是一個具備所有 GC 特性的垃圾回收器,因此將 G1 設定為 JVM 預設的 GC。

根據 JEP-291 中的說明,為了減輕 GC 程式碼的維護負擔以及加速新功能開發,決定在 JDK 9 中廢棄 CMS GC。

從 Java 9 開始,如果您使用 -XX:+UseConcMarkSweepGC(啟用 CMS GC 演算法的引數)引數啟動應用程式,則會在下面顯示警告訊息:

Java HotSpot(TM) 64-Bit Server VM warning: Option UseConcMarkSweepGC was deprecated in version 9.0 and will likely be removed in a future release.

如果你想知道當前應用對應的 JVM 版本,你可以使用以下命令進行查詢:

G1將整個JVM堆劃分成多個大小相等的獨立區域regin,跟蹤各個regin裡面的垃圾堆積的價值大小,在後臺維護一個優先列表,每次根據允許的收集時間,有線回收最大的regin,芮然還保留有新生代和老年代的概念,但新生代和老年代不在是物理隔離了,他們都是一部分regin集合。

記憶體“化整為零”的思路:在GC根節點的列舉範圍彙總加入remembered set 即可保證不對全堆掃面也不會遺漏。

「回收步驟」

初始標記:標記GC Roots直接關聯的物件併發標記:對堆中物件進行可達性分析,找出存活物件,耗時長,與使用者程序併發工作最終標記:修正併發標記期間使用者程序繼續執行而產生變化的標記篩選回收:對各個regin的回收價值進行排序,然後根據期望的GC停頓時間制定回收計劃

G1收集器優勢

「並行與併發」:G1能充分利用多CPU、多核環境下的硬體優勢,使用多個CPU來縮短Stop-The-World停頓時間。部分收集器原本需要停頓Java執行緒來執行GC動作,G1收集器仍然可以透過併發的方式讓Java程式繼續執行。

「分代收集」:G1能夠獨自管理整個Java堆,並且採用不同的方式去處理新建立的物件和已經存活了一段時間、熬過多次GC的舊物件以獲取更好的收集效果。

「空間整合」:G1運作期間不會產生空間碎片,收集後能提供規整的可用記憶體。

「可預測的停頓」:G1除了追求低停頓外,還能建立可預測的停頓時間模型。能讓使用者明確指定在一個長度為M毫秒的時間段內,消耗在垃圾收集上的時間不得超過N毫秒。

收集過程:

G1的回收過程主要分為 3 類:

(1)G1“年輕代”的垃圾回收,同樣叫 Minor G1,這個過程和我們前面描述的類似,發生時機就是 Eden 區滿的時候。

(2)老年代的垃圾收集,嚴格上來說其實不算是收集,它是一個“併發標記”的過程,順便清理了一點點物件。

(3)真正的清理,發生在“混合模式”,它不止清理年輕代,還會將老年代的一部分割槽域進行清理。

ZGC

ZGC(Z Garbage Collector)是一款由Oracle公司研發的,以低延遲為首要目標的一款垃圾收集器。它是基於「動態Region」記憶體佈局,(暫時)「不設年齡分代」,使用了「讀屏障」「染色指標」「記憶體多重對映」等技術來實現「可併發的標記-整理演算法」的收集器。

在JDK 11新加入,還在實驗階段,主要特點是:「回收TB級記憶體(最大4T),停頓時間不超過10ms」

「優點」:低停頓,高吞吐量,ZGC收集過程中額外耗費的記憶體小

「缺點」:浮動垃圾

目前使用的非常少,真正普及還是需要寫時間的。

21.垃圾收集器之間有什麼關係?

「新生代收集器」:Serial、ParNew、Parallel Scavenge

「老年代收集器」:CMS、Serial Old、Parallel Old

「整堆收集器」:G1,ZGC(因為不涉年代不在圖中)

22.如何選擇垃圾收集器?

選擇建議:

如果你的堆大小不是很大(比如 100MB),選擇序列收集器一般是效率最高的。引數:-XX:+UseSerialGC。如果你的應用執行在單核的機器上,或者你的虛擬機器核數只有 單核,選擇序列收集器依然是合適的,這時候啟用一些並行收集器沒有任何收益。引數:-XX:+UseSerialGC。如果你的應用是“吞吐量”優先的,並且對較長時間的停頓沒有什麼特別的要求。選擇並行收集器是比較好的。引數:-XX:+UseParallelGC。如果你的應用對響應時間要求較高,想要較少的停頓。甚至 1 秒的停頓都會引起大量的請求失敗,那麼選擇G1、ZGC、CMS都是合理的。雖然這些收集器的 GC 停頓通常都比較短,但它需要一些額外的資源去處理這些工作,通常吞吐量會低一些。引數:-XX:+UseConcMarkSweepGC、-XX:+UseG1GC、-XX:+UseZGC 等。

從上面這些出發點來看,我們平常的 Web 伺服器,都是對響應性要求非常高的。選擇性其實就集中在 CMS、G1、ZGC上。而對於某些定時任務,使用並行收集器,是一個比較好的選擇。

23.熟悉哪些JVM調優引數?

X或者XX開頭的都是非轉標準化引數

意思就是說準表化引數不會變,非標準化引數可能在每個JDK版本中有所變化,但是就目前來看X開頭的非標準化的引數改變的也是非常少。

格式:-XX:[+-]<name> 表示啟用或者禁用name屬性。例子:-XX:+UseG1GC(表示啟用G1垃圾收集器)
堆設定

-Xms 初始堆大小,ms是memory start的簡稱 ,等價於-XX:InitialHeapSize-Xmx 最大堆大小,mx是memory max的簡稱 ,等價於引數-XX:MaxHeapSize

注意:在通常情況下,伺服器專案在執行過程中,對空間會不斷的收縮與擴張,勢必會造成不必要的系統壓力。所以在生產環境中,JVM的Xms和Xmx要設定成一樣的,能夠避免GC在調整堆大小帶來的不必要的壓力。

-XX:NewSize=n 設定年輕代大小-XX:NewRatio=n 設定年輕代和年老代的比值。如:-XX:NewRatio=3,表示年輕代與年老代比值為1:3,年輕代佔整個年輕代年老代和的1/4,預設新生代和老年代的比例=1:2。-XX:SurvivorRatio=n 年輕代中Eden區與兩個Survivor區的比值。注意Survivor區有兩個,預設是8,表示

Eden:S0:S1=8:1:1

如:-XX:SurvivorRatio=3,表示Eden:Survivor=3:2,一個Survivor區佔整個年輕代的1/5。

-XX:MaxPermSize=n 設定持久代大小

-XX:MetaspaceSize 設定元空間大小

收集器設定

-XX:+UseSerialGC 設定序列收集器-XX:+UseParallelGC 設定並行收集器-XX:+UseParalledlOldGC 設定並行年老代收集器-XX:+UseConcMarkSweepGC 設定併發收集器

垃圾回收統計資訊

-XX:+PrintGC-XX:+PrintGCDetails-XX:+PrintGCTimeStamps-Xloggc:filenameGC日誌輸出到檔案裡filename,比如:-Xloggc:/gc.log

並行收集器設定

-XX:ParallelGCThreads=n 設定並行收集器收集時使用的CPU數。並行收集執行緒數。

-XX:MaxGCPauseMillis=n 設定並行收集最大暫停時間

-XX:GCTimeRatio=n 設定垃圾回收時間佔程式執行時間的百分比。公式為1/(1+n)

-XX:MaxGCPauseMillis=n設定並行收集最大暫停時間

併發收集器設定

-XX:+CMSIncrementalMode 設定為增量模式。適用於單CPU情況。-XX:ParallelGCThreads=n 設定併發收集器年輕代收集方式為並行收集時,使用的CPU數。並行收集執行緒數。

其他

-XX:+PrintCommandLineFlags檢視當前JVM設定過的相關引數

Dump異常快照

-XX:+HeapDumpOnOutOfMemoryError

-XX:HeapDumpPath

堆記憶體出現OOM的機率是所有記憶體耗盡異常中最高的,出錯時的堆內資訊對解決問題非常有幫助,所以給JVM設定這個引數(-XX:+HeapDumpOnOutOfMemoryError),讓JVM遇到OOM異常時能輸出堆內資訊,並透過(-XX:+HeapDumpPath)引數設定堆記憶體溢位快照輸出的檔案地址,這對於特別是對相隔數月才出現的OOM異常尤為重要。

-Xms10M -Xmx10M -Xmn2M -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\study\log_hprof\gc.hprof

-XX:OnOutOfMemoryError

表示發生OOM後,執行jconsole.exe程式。這裡可以不用加“”,因為jconsole.exe路徑Program Files含有空格。利用這個引數,我們可以在系統OOM後,自定義一個指令碼,可以用來發送郵件告警資訊,可以用來重啟系統等等。

-XX:OnOutOfMemoryError="C:\Program Files\Java\jdk1.8.0_151\bin\jconsole.exe"
24.8G記憶體的伺服器該如何設定?
java -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4 -XX:MaxPermSize=16m -XX:MaxTenuringThreshold=0

-Xmx3500m 設定JVM最大可用記憶體為3550M。

-Xms3500m 設定JVM促使記憶體為3550m。此值可以設定與-Xmx相同,以避免每次垃圾回收完成後JVM重新分配記憶體。-Xmn2g 設定年輕代大小為2G。

整個堆大小=年輕代大小 + 年老代大小 + 方法區大小

-Xss128k 設定每個執行緒的堆疊大小。JDK1.5以後每個執行緒堆疊大小為1M,以前每個執行緒堆疊大小為256K。根據應用的執行緒所需記憶體大小進行調整。在相同物理記憶體下,減小這個值能生成更多的執行緒。但是作業系統對一個程序內的執行緒數還是有限制的,不能無限生成,經驗值在3000~5000左右。

-XX:NewRatio=4 設定年輕代(包括Eden和兩個Survivor區)與年老代的比值(除去持久代)。設定為4,則年輕代與年老代所佔比值為1:4,年輕代佔整個堆疊的1/5 。

-XX:SurvivorRatio=4 設定年輕代中Eden區與Survivor區的大小比值。設定為4,則兩個Survivor區與一個Eden區的比值為2:4,一個Survivor區佔整個年輕代的1/6 -XX:MaxPermSize=16m 設定持久代大小為16m。

-XX:MaxTenuringThreshold=0 設定垃圾最大年齡。如果設定為0的話,則年輕代物件不經過Survivor區,直接進入年老代。對於年老代比較多的應用,可以提高效率。如果將此值設定為一個較大值,則年輕代物件會在Survivor區進行多次複製,這樣可以增加物件在年輕代的存活時間,增加在年輕代即被回收的概論。

13
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • BIOS Std 1275-1994 P20