淺談SUN JVM內存管理與應用服務器的優化 之SUN JVM內存管理

JVM(Java Virtual Machine):Java虛擬機,所有的Java程序都在Java虛擬機中運行。
元數據:在本文中指用於描述類和接口定義的數據。

在我做J2EE系統開發的工作生涯中,經常遇到技術人員或客戶發出諸如此類的感慨:我的J2EE應用系統處理的數據量不大,系統體積也不大,技術架構也沒有問題,我的應用服務器的內存有4G或8G;系統運行起來很慢,還經常出現內存溢出錯誤。真是無奈!每次遇到這樣的情況,我心中都會忍不住竊笑之。

其實他們所遇到這種情況,不是技術架構上的問題,不是系統本身的問題,也不是應用服務器的問題,也可能不是服務器的內存資源真的不足的問題。他們花了很多時間在J2EE應用系統本身上找問題(當然一般情況下,這種做法是對的;當出現問題時,在自身上多找找有什麼不足),結果還是解決不了問題。他們卻忽略了很重要的一點:J2EE應用系統是運行在J2EE應用服務器上的,而J2EE應用服務器又是運行在JVM(Java Virtual Machine)上的。
其實在生產環境中JVM參數的優化和設置對J2EE應用系統性能有着決定性的作用。本篇我們就來分析JAVA的創建者SUN 公司的JVM的內存管理機制(在現實中絕大多數的應用服務器是運行在SUN公司的JVM上的,當然除了SUN公司的JVM,還有IBM的JVM,Bea的JVM等);下篇咱們具體講解怎樣優化JVM的參數以達到優化J2EE應用的目的。
咱們先來看JVM的內存管理制吧,JVM的早期版本並沒有進行分區管理;這樣的後果是JVM進行垃圾回收時,不得不掃描JVM所管理的整片內存,所以蒐集垃圾是很耗費資源的事情,也是早期JAVA程序的性能低下的主要原因。隨着JVM的發展,JVM引進了分區管理的機制。
採用分區管理機制的JVM將JVM所管理的所有內存資源分爲2個大的部分。永久存儲區(Permanent Space)和堆空間(The Heap Space)。其中堆空間又分爲新生區(Young (New) generation space)和養老區(Tenure (Old) generation space),新生區又分爲伊甸園(Eden space),倖存者0區(Survivor 0 space)和倖存者1區(Survivor 1 space)。具體分區如下圖:

 

 

 


那JVM他的這些分區各有什麼用途,請看下面的解說。
永久存儲區(Permanent Space):永久存儲區是JVM的駐留內存,用於存放JDK自身所攜帶的Class,Interface的元數據,應用服務器允許必須的Class,Interface的元數據和Java程序運行時需要的Class和Interface的元數據。被裝載進此區域的數據是不會被垃圾回收器回收掉的,關閉JVM時,釋放此區域所控制的內存。

堆空間(The Heap Space):是JAVA對象生死存亡的地區,JAVA對象的出生,成長,死亡都在這個區域完成。堆空間又分別按JAVA對象的創建和年齡特徵分爲養老區和新生區。

新生區(Young (New) generation space):新生區的作用包括JAVA對象的創建和從JAVA對象中篩選出能進入養老區的JAVA對象。

伊甸園(Eden space):JAVA對空間中的所有對象在此出生,該區的名字因此而得名。也即是說當你的JAVA程序運行時,需要創建新的對象,JVM將在該區爲你創建一個指定的對象供程序使用。創建對象的依據即是永久存儲區中的元數據。

倖存者0區(Survivor 0 space)和倖存者1區(Survivor1 space):當伊甸園的控件用完時,程序又需要創建對象;此時JVM的垃圾回收器將對伊甸園區進行垃圾回收,將伊甸園區中的不再被其他對象所引用的對象進行銷燬工作。同時將伊甸園中的還有其他對象引用的對象移動到倖存者0區。倖存者0區就是用於存放伊甸園垃圾回收時所幸存下來的JAVA對象。當將伊甸園中的還有其他對象引用的對象移動到倖存者0區時,如果倖存者0區也沒有空間來存放這些對象時,JVM的垃圾回收器將對倖存者0區進行垃圾回收處理,將倖存者0區中不在有其他對象引用的JAVA對象進行銷燬,將倖存者0區中還有其他對象引用的對象移動到倖存者1區。倖存者1區的作用就是用於存放倖存者0區垃圾回收處理所幸存下來的JAVA對象。

養老區(Tenure (Old) generation space):用於保存從新生區篩選出來的JAVA對象。
上面我們看了JVM的內存分區管理,現在我們來看JVM的垃圾回收工作是怎樣運作的。首先當啓動J2EE應用服務器時,JVM隨之啓動,並將JDK的類和接口,應用服務器運行時需要的類和接口以及J2EE應用的類和接口定義文件也及編譯後的Class文件或JAR包中的Class文件裝載到JVM的永久存儲區。在伊甸園中創建JVM,應用服務器運行時必須的JAVA對象,創建J2EE應用啓動時必須創建的JAVA對象;J2EE應用啓動完畢,可對外提供服務。
JVM在伊甸園區根據用戶的每次請求創建相應的JAVA對象,當伊甸園的空間不足以用來創建新JAVA對象的時候,JVM的垃圾回收器執行對伊甸園區的垃圾回收工作,銷燬那些不再被其他對象引用的JAVA對象(如果該對象僅僅被一個沒有其他對象引用的對象引用的話,此對象也被歸爲沒有存在的必要,依此類推),並將那些被其他對象所引用的JAVA對象移動到倖存者0區。
如果倖存者0區有足夠控件存放則直接放到倖存者0區;如果倖存者0區沒有足夠空間存放,則JVM的垃圾回收器執行對倖存者0區的垃圾回收工作,銷燬那些不再被其他對象引用的JAVA對象(如果該對象僅僅被一個沒有其他對象引用的對象引用的話,此對象也被歸爲沒有存在的必要,依此類推),並將那些被其他對象所引用的JAVA對象移動到倖存者1區。
如果倖存者1區有足夠控件存放則直接放到倖存者1區;如果倖存者0區沒有足夠空間存放,則JVM的垃圾回收器執行對倖存者0區的垃圾回收工作,銷燬那些不再被其他對象引用的JAVA對象(如果該對象僅僅被一個沒有其他對象引用的對象引用的話,此對象也被歸爲沒有存在的必要,依此類推),並將那些被其他對象所引用的JAVA對象移動到養老區。
如果養老區有足夠控件存放則直接放到養老區;如果養老區沒有足夠空間存放,則JVM的垃圾回收器執行對養老區區的垃圾回收工作,銷燬那些不再被其他對象引用的JAVA對象(如果該對象僅僅被一個沒有其他對象引用的對象引用的話,此對象也被歸爲沒有存在的必要,依此類推),並保留那些被其他對象所引用的JAVA對象。如果到最後養老區,倖存者1區,倖存者0區和伊甸園區都沒有空間的話,則JVM會報告“JVM堆空間溢出(java.lang.OutOfMemoryError: Java heap space)”,也即是在堆空間沒有空間來創建對象。
這就是JVM的內存分區管理,相比不分區來說;一般情況下,垃圾回收的速度要快很多;因爲在沒有必要的時候不用掃描整片內存而節省了大量時間。
通常大家還會遇到另外一種內存溢出錯誤“永久存儲區溢出(java.lang.OutOfMemoryError: Java Permanent Space)”。
好,本篇對SUN 的JVM內存管理機制講解就到此爲止,下一篇我們將詳細講解怎樣優化SUN 的JVM讓我們的J2EE系統運行更快,不出現內存溢出等問題。

發佈了12 篇原創文章 · 獲贊 0 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章