Java虛擬機器6:記憶體溢位和記憶體洩露、並行和併發、Minor GC和Full GC、Client模式和Server模式的區別

五月的倉頡發表於2015-09-26

前言

之前的文章尤其是講解GC的時候提到了很多的概念,比如記憶體溢位和記憶體洩露、並行與併發、Client模式和Server模式、Minor GC和Full GC,本文詳細講解下這些概念的區別。

 

記憶體溢位和記憶體洩露的區別

1、記憶體溢位

記憶體溢位指的是程式在申請記憶體的時候,沒有足夠大的空間可以分配了。

2、記憶體洩露

記憶體洩露指的是程式在申請記憶體之後,沒有辦法釋放掉已經申請到記憶體,它始終佔用著記憶體,即被分配的物件可達但無用。記憶體洩露一般都是因為記憶體中有一塊很大的物件,但是無法釋放。

從定義上可以看出,記憶體洩露終將導致記憶體溢位。

注意,定位虛擬機器問題記憶體問題的時候第一步就是要判斷到底是記憶體溢位還是記憶體洩露,前者好判斷,跟蹤堆疊資訊就可以了;後者比較複雜一點,一般都是老年代中的大物件沒釋放掉,要通過各種辦法找出老年代中的大物件沒有被釋放的原因。

 

並行和併發的區別

這兩個名詞都是併發程式設計中的概念,在談論垃圾收集器的上下文語境中,可以這麼理解這兩個名詞:

1、並行Parallel

多條垃圾收集執行緒並行工作,但此時使用者執行緒仍然處於等待狀態

2、併發Concurrent

指使用者執行緒與垃圾收集執行緒同時執行(但並不一定是並行的,可能會交替執行),使用者程式在繼續執行,而垃圾收集程式執行於另一個CPU上

 

Minor GC和Full GC的區別

1、新生代GC(Minor GC)

指發生在新生代的垃圾收集動作,因為大多數Java物件存活率都不高,所以Minor GC非常頻繁,一般回收速度也比較快

2、老年代GC(Major GC/Full GC)

指發生在老年代的垃圾收集動作,出現了Major GC,經常會伴隨至少一次的Minor GC(但並不是絕對的)。Major GC的速度一般要比Minor GC慢上10倍以上

 

Client模式和Server模式的區別

部分商用虛擬機器中,Java程式最初是通過直譯器對.class檔案進行解釋執行的,當虛擬機器發現某個方法或程式碼塊執行地特別頻繁的時候,就會把這些程式碼認定為熱點程式碼Hot Spot Code(這也是我們使用的虛擬機器HotSpot名稱的由來)。為了提高熱點程式碼的執行效率,在執行時,虛擬機器將會把這些程式碼編譯成與本地平臺相關的機器碼,並進行各種層次的優化,完成這個任務的編譯器叫做即時編譯器(Just In Time Compiler,即JIT編譯器)。JIT編譯器並不是虛擬機器必需的部分,Java虛擬機器規範並沒有要求要有JIT編譯器的存在,更沒有限定或指導JIT編譯器應該如何去實現。但是,JIT編譯器效能的好壞、程式碼優化程度的高低卻是衡量一款商用虛擬機器優秀與否的最關鍵指標之一。

直譯器和編譯器其實和編譯器各有優勢:

1、當程式需要迅速啟動和執行的時候,直譯器可以先發揮作用,省去編譯的時間,立即執行

2、在程式執行後,隨著時間的推移,編譯器逐漸發揮作用,把越來越多的程式碼編譯成原生程式碼之後,可以獲取更高的執行效率

我們使用的HotSpot中內建了兩個JIT編譯器,即C1編譯器和C2編譯器,預設採用的是直譯器和一個編輯器配合的方式進行工作。HotSpot在啟動的時候會根據自身版本以及宿主機器的硬體效能自動選擇執行模式,比如會檢測宿主機器是否為伺服器、比如J2SE會檢測主機是否有至少2個CPU和至少2GB的記憶體。

1、如果是,則虛擬機器會以Server模式執行,該模式與C2編譯器共同執行,更注重編譯的質量,啟動速度慢,但是執行效率高,適合用在伺服器環境下,針對生產環境進行了優化

2、如果不是,則虛擬機器會以Client模式執行,該模式與C1編譯器共同執行,更注重編譯的速度,啟動速度快,更適合用在客戶端的版本下,針對GUI進行了優化

有兩種方法檢視虛擬機器是執行在Client模式下還是Server模式下:

1、在程式命令列執行“java -version”命令,檢視的是你本地安裝的虛擬機器是資訊

2、比如我們用Eclipse或者MyEclipse執行程式,一般使用的都是工具自帶的JRE,虛擬機器並不是本地安裝的虛擬機器。這時候怎麼辦呢,可以通過在程式中執行下面的語句來檢視虛擬機器資訊

System.out.println(System.getProperty("java.vm.name"));

我這裡的執行結果是

Java HotSpot(TM) 64-Bit Server VM

當然要改變虛擬機器執行的模式也可以,只需要改jvm.cfg就可以了。我們可以從以下幾個地方找到jvm.cfg:

1、32位的JDK的檔案路徑是  JAVA_HOME/jre/lib/i386/jvm.cfg

2、64位的JDK的檔案路徑是  JAVA_HOME/jre/lib/amd64/jvm.cfg

3、MyEclipse在 .../Common/binary/com.sun.java.jdk.win32.x86_64_1.6.0.013/jre/lib/amd64/jvm.cfg

目前64位只支援Server模式,檔案內容都是一樣的,上面的註釋不去管它,剩下的就是這些:

-server KNOWN
-client IGNORE
-hotspot ALIASED_TO -server
-classic WARN
-native ERROR
-green ERROR

由於我的電腦裝的是64位JDK,所以是“-client INGORE”。同時支援Server模式和Client模式的,應該是“-server KNOWN”和“-client KNOWN”,一般只需要變更這兩個配置的先後順序即可,但是前提是JAVA_HOME/jre/bin目錄下同時存在server和client兩個資料夾,分別對應著各自的虛擬機器,缺少一個,切換後就會報錯。

相關文章