Java虛擬機6:內存溢出和內存泄露、並行和併發

前言

之前的文章尤其是講解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”命令,查看的是你本地安裝的虛擬機是信息

Java虛擬機6:內存溢出和內存泄露、並行和併發

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兩個文件夾,分別對應着各自的虛擬機,缺少一個,切換後就會報錯。

相關文章