tomcat學習筆記

第一章 JVM原理

一、什麼是JVM

    JVM是Java Virtual Machine(Java虛擬機)的縮寫。

        JAVA語言的平臺無關性如何實現:通過Java虛擬機,Java語言在不同平臺上運行時不需要重新編譯。Java語言使用Java虛擬機屏蔽了與具體平臺相關的信息,使得Java語言編譯程序只需生成在Java虛擬機上運行的目標代碼(字節碼),就可以在多種平臺上不加修改地運行。Java虛擬機在執行字節碼時,把字節碼解釋成具體平臺上的機器指令執行。這就是Java的能夠“一次編譯,到處運行”的原因。

wKiom1lcxZiDAo60AADr2hcDLtQ274.gif

上圖爲 JVM結構圖

二、JAVA代碼編譯和執行過程

    JAVA代碼編譯和執行包含如下三個過程:


    1.  Java源碼編譯機制

    2.   類加載機制

    3.   類執行機制

     java源碼編譯機制

        最終將.java文件編譯生成.class文件

     類加載機制

        JVM的類通過ClassLoader及其子類來完成類加載的過程,類的層次關係和加載順序可以由下圖來描述:

wKiom1lcyQCCD7NbAALSslgvan4053.gif

        (1)Bootstrap ClassLoader

                負責加載$JAVA_HOME中jre/lib/rt.jar裏所有的class,由C++實現,不是ClassLoader子類

        (2)Extension ClassLoader

                負責加載java平臺中擴展功能的一些jar包,包括$JAVA_HOME中jre/lib/*.jar或-Djava.ext.dirs指定目錄下的jar包

        (3)App ClassLoader

                負責記載classpath中指定的jar包及目錄中class

        (4)Custom ClassLoader

                屬於應用程序根據自身需要自定義的ClassLoader,如tomcat、jboss都會根據j2ee規範自行實現ClassLoader加載過程中會先檢查類是否被已加載,檢查順序是自底向上,從Custom ClassLoader到BootStrap ClassLoader逐層檢查,只要某個classloader已加載就視爲已加載此類,保證此類只所有ClassLoader加載一次。而加載的順序是自頂向下,也就是由上層來逐層嘗試加載此類。

    類執行機制

        JVM是基於棧的體系結構來執行class字節碼的。線程創建後,都會產生程序計數器(PC)和棧(Stack),程序計數器存放下一條要執行的指令在方法內的偏移量,棧中存放一個個棧幀,每個棧幀對應着每個方法的每次調用,而棧幀又是有局部變量區和操作數棧兩部分組成,局部變量區用於存放方法中的局部變量和參數,操作數棧中用於存放方法執行過程中產生的中間結果。


三、JVM內存管理和垃圾回收

    JVM棧有堆、棧、本地方法棧、方法區組成,結構如圖

wKiom1lcyzXTYrzxAABJZl9oGcI720.gif

1)堆

    所有通過new創建的對象的內存都在堆中分配,堆的大小可以通過-Xmx和-Xms來控制。

        堆分爲新生代老年代持久帶,新生代分爲EdenSurvivor(Survivor又分爲fromto)

        

wKioL1lczOrCrAtpAAB_AJnDzPk932.gif

    新生代:新建的對象都是用新生代分配內存,Eden空間不足的時候,會把存活的對象轉移到Survivor中,新生代大小可以由-Xmn來控制,也可以用-XX:SurvivorRatio來控制Eden和Survivor的比例

        老年代:用於存放新生代中經過多次垃圾回收仍然存活的對象

        持久帶(Permanent Space):主要存放所有已加載的類信息,方法信息,常量池等等。可通過-XX:PermSize和-XX:MaxPermSize來指定持久帶初始化值和最大值。Permanent Space並不等同於方法區,只不過是Hotspot JVM用Permanent Space來實現方法區而已,有些虛擬機沒有Permanent Space而用其他機制來實現方法區。

wKioL1lczfHgIQhZAAEPoE1ZJmE973.jpg

-Xmx:最大堆內存,如:-Xmx512m

-Xms:初始時堆內存,如:-Xms256m

-XX:MaxNewSize:最大年輕區內存

-XX:NewSize:初始時年輕區內存.通常爲 Xmx 的 1/3 或 1/4。新生代 = Eden + 2 個 Survivor 空間。實際可用空間爲 = Eden + 1 個 Survivor,即 90%

-XX:MaxPermSize:最大持久帶內存

-XX:PermSize:初始時持久帶內存

-XX:+PrintGCDetails。打印 GC 信息

-XX:NewRatio 新生代與老年代的比例,如 –XX:NewRatio=2,則新生代佔整個堆空間的1/3,老年代佔2/3

-XX:SurvivorRatio 新生代中 Eden 與 Survivor 的比值。默認值爲 8。即 Eden 佔新生代空間的 8/10,另外兩個 Survivor 各佔 1/10


2)棧

     每個線程執行每個方法的時候都會在棧中申請一個棧幀,每個棧幀包括局部變量區和操作數棧,用於存放此次方法調用過程中的臨時變量、參數和中間結果。

    -xss:設置每個線程的堆棧大小. JDK1.5+ 每個線程堆棧大小爲 1M,一般來說如果棧不是很深的話, 1M 是絕對夠用了的。

3)本地方法棧

    用於支持native方法的執行,存儲了每個native方法調用的狀態

4)方法區

    存放了要加載的類信息、靜態變量、final類型的常量、屬性和方法信息。JVM用持久代(Permanet Generation)來存放方法區,可通過-XX:PermSize和-XX:MaxPermSize來指定最小值和最大值

-------------------------------------------------------------------------------------------------------------------------------------

JVM垃圾回收

    JVM垃圾回收策略:引用計數、標記-清除、複製、標記-整理

    JVM垃圾回收器:串行收集器、並行收集器、併發收集器

四、JVM內存調優

    對JVM內存的系統級的調優主要的目的是減少GC的頻率和Full GC的次數,過多的GC和Full GC是會佔用很多的系統資源(主要是CPU),影響系統的吞吐量。

 

新生代設置過小會導致如下後果

1、新生代GC次數頻繁,增大系統消耗

2、導致大對象直接進入老年代,佔據老年代剩餘空間,易誘發Full GC


新生代設置過大會導致如下後果

1、導致老年代過小(heap總量一定),易誘發Full GC

2、新生代GC耗時大幅度增加

一般說來新生代佔整個堆1/3比較合適


Survivor設置過小會導致如下後果

導致對象從eden直接到達老年代,降低了在新生代的存活時間


Survivor設置過大會導致如下後果

導致eden過小,增加了GC頻率




當以吞吐量優先時的調優策略:

JVM以吞吐量爲指標,自行選擇相應的GC策略及控制新生代與舊生代的大小比例,來達到吞吐量指標。這個值可由-XX:GCTimeRatio=n來設置

當以暫停時間優先時的調優策略:

JVM以暫停時間爲指標,自行選擇相應的GC策略及控制新生代與舊生代的大小比例,儘量保證每次GC造成的應用停止時間都在指定的數值範圍內完成。這個值可由-XX:MaxGCPauseRatio=n來設置


例子:設置tomcat內存大小

直接在catalina.sh腳本最前方增加
JAVA_OPTS='-Xms1024m -Xmx1024m -XX:PermSize=128m  -XX:MaxPermSize=256m'
將xms和xmx設置一樣大,省着經常內存回收


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章