Tomcat環境及線程池、jdk配置詳解

gww3 9年前發布 | 42K 次閱讀 Tomcat 應用服務器

tomcat 環境及線程池、jdk配置詳解
一、常見的Java內存溢出有以下三種:

  1. JVM Heap(堆)溢出:java.lang.OutOfMemoryError: Java heap space
    JVM在啟動的時候會自動設置JVM Heap的值,其初始空間(即-Xms)是物理內存的1/64,最大空間(-Xmx)不可超過物理內存。
    可以利用JVM提供的-Xmn -Xms -Xmx等選項可進行設置。Heap的大小是Young Generation 和Tenured Generaion 之和。
    在JVM中如果98%的時間是用于GC,且可用的Heap size 不足2%的時候將拋出此異常信息。
    解決方法:手動設置JVM Heap(堆)的大小 </p>

    2. PermGen space溢出:java.lang.OutOfMemoryError: PermGen space
    PermGen space的全稱是Permanent Generation space,是指內存的永久保存區域。
    為什么會內存溢出,這是由于這塊內存主要是被JVM存放Class和Meta信息的,Class在被Load的時候被放入PermGen space區域,它和存放Instance的Heap區域不同,sun的 GC不會在主程序運行期對PermGen space進行清理,所以如果你的APP會載入很多CLASS的話,就很可能出現PermGen space溢出。
    解決方法:手動設置MaxPermSize大小

    3. 棧溢出:java.lang.StackOverflowError
    棧溢出了,JVM依然是采用棧式的虛擬機,這個和C和Pascal都是一樣的。函數的調用過程都體現在堆棧和退棧上了。
    調用構造函數的 “層”太多了,以致于把棧區溢出了。
    通常來講,一般棧區遠遠小于堆區的,因為函數調用過程往往不會多于上千層,而即便每個函數調用需要 1K的空間(這個大約相當于在一個C函數內聲明了256個int類型的變量),那么棧區也不過是需要1MB的空間。通常棧的大小是1-2MB的。
    通常遞歸也不要遞歸的層次過多,很容易溢出。
    解決方法:修改程序。

    二、解決方法
    在生產環境中tomcat內存設置不好很容易出現jvm內存溢出。
    1、 linux下的tomcat 位于cygwin=false前
    修改TOMCAT_HOME/bin/catalina.sh
    export JAVA_HOME="/usr/local/jdk"
    export JRE_HOME="/usr/local/jdk/jre"

    # OS specific support.  $var _must_ be set to either true or false.
    .............
    .............
    # Get standard environment variables
    PRGDIR=`dirname "$PRG"`

    # Only set CATALINA_HOME if not already set
    [ -z "$CATALINA_HOME" ] && CATALINA_HOME=`cd "$PRGDIR/.." >/dev/null; pwd`

    # Copy CATALINA_BASE from CATALINA_HOME if not already set
    [ -z "$CATALINA_BASE" ] && CATALINA_BASE="$CATALINA_HOME"

    export CATALINA_OPTS="-server -Xss512k -Xms1024M -Xmx1024M -XX:PermSize=128M -XX:MaxPermSize=256M -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:ParallelGCThreads=8 -verbose:gc -Xloggc:$CATALINA_BASE/logs/gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$CATALINA_BASE/ -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=10001 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false"

    三、jvm參數說明:
    -server:一定要作為第一個參數,因為tomcat默認是以一種叫java –client的模式來運行的,server即意味著你的tomcat是以真實的production的模式在運行的
    -Xms:java Heap初始大小。把Xms與Xmx兩個值設成一樣是最優的做法。
    -Xmx:java heap最大值。把Xms與Xmx兩個值設成一樣是最優的做法。
    -XX:PermSize:設定內存的永久保存區初始大小,缺省值為64M。
    -XX:MaxPermSize:設定內存的永久保存區最大 大小,缺省值為64M。
    -XX:SurvivorRatio=2  :生還者池的大小,默認是2,如果垃圾回收變成了瓶頸,您可以嘗試定制生成池設置
    -XX:NewSize: 新生成的池的初始大小。 缺省值為2M。
    -XX:MaxNewSize: 新生成的池的最大大小。   缺省值為32M。
    如果 JVM 的堆大小大于 1GB,則應該使用值:-XX:newSize=640m -XX:MaxNewSize=640m -XX:SurvivorRatio=16,或者將堆的總大小的 50% 到 60% 分配給新生成的池。調大新對象區,減少Full GC次數。
    +XX:AggressiveHeap 會使得 Xms沒有意義。這個參數讓jvm忽略Xmx參數,瘋狂地吃完一個G物理內存,再吃盡一個G的swap。
    -Xss:每個線程的Stack大小,“-Xss 15120” 這使得JBoss每增加一個線程(thread)就會立即消耗15M內存,而最佳值應該是128K,默認值好像是512k.
    -verbose:gc 現實垃圾收集信息
    -Xloggc:gc.log 指定垃圾收集日志文件
    -Xmn:young generation的heap大小,一般設置為Xmx的3、4分之一 ,整個堆大小=年輕代大小 + 年老代大小 + 持久代大小。持久代一般固定大小為64m,所以增大年輕代后,將會減小年老代大小。此值對系統性能影響較大,Sun官方推薦配置為整個堆的3/8。
    -XX:+UseParNewGC :縮短minor收集的時間
    -XX:+UseConcMarkSweepGC :縮短major收集的時間 此選項在Heap Size 比較大而且Major收集時間較長的情況下使用更合適。
    -XX:userParNewGC 可用來設置并行收集【多CPU】
    -XX:ParallelGCThreads 可用來增加并行度【多CPU】
    -XX:UseParallelGC 設置后可以使用并行清除收集器【多CPU】
    使用JVisualVM遠程監控Tomcat在tomcat的catalina.sh 中添加如下參數:
    set JAVA_OPTS=-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port="9004" -Dcom.sun.management.jmxremote.authenticate="false" -Dcom.sun.management.jmxremote.ssl="false"
    -Dcom.sun.management.jmxremote.port=9004 指定了 JMX 啟動的代理端口;這個端口就是 Visual VM 要連接的端口
    -Dcom.sun.management.jmxremote.ssl ="false" 指定了 JMX 是否啟用ssl
    -Dcom.sun.management.jmxremote.authenticate =false指定了不需要密碼認證連接
     
    四、線程池配置:在./conf/server.xml中:
    搜索【<Executor name="tomcatThreadPool"】,開啟并調整為:最大線程500(一般服務器足以),最小空閑線程數20,線程最大空閑時間60秒。
        <!--2015/03/03 14:32 changee by wangyingchun -->
        <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
            maxThreads="600" minSpareThreads="30" maxIdleTime="60000" />

    搜索【port="8080"】,開啟并修改<Connector ...>節點,增加executor屬性,如:
        <!--2015/03/03 14:32 changee by wangyingchun -->
        <Connector executor="tomcatThreadPool"
                   port="8001" protocol="HTTP/1.1"
                   connectionTimeout="60000"
                   redirectPort="443"  URIEncoding="UTF-8"
                   minSpareThreads="30"
                   maxSpareThreads="300"
                   enableLookups="false"
                   disableUploadTimeout="true"
                   compression="on" compressionMinSize="4096"
                   noCompressionUserAgents="gozilla, traviata"
                   compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain,application/json,application/x-javascript"
                   maxThreads="600" />
           
    maxThreads:Tomcat可創建的最大的線程數,每一個線程處理一個請求;
    minSpareThreads:最小備用線程數,tomcat啟動時的初始化的線程數;
    maxSpareThreads:最大備用線程數,一旦創建的線程超過這個值,Tomcat就會關閉不再需要的socket線程;
    acceptCount:指定當所有可以使用的處理請求的線程數都被使用時,可以放到處理隊列中的請求數,
    就是被排隊的請求數,超過這個數的請求將拒絕連接。
    connnectionTimeout:網絡連接超時,單位:毫秒。設置為0表示永不超時,這樣設置有隱患的。通常可設置為30000毫秒。
    enableLookups:是否允許DNS查詢
    URIEncoding=”UTF-8” 使得tomcat可以解析含有中文名的文件的url
    maxSpareThreads 的意思就是如果空閑狀態的線程數多于設置的數目,則將這些線程中止,減少這個池中的線程總數。
    minSpareThreads 最小備用線程數,tomcat啟動時的初始化的線程數。
    enableLookups 這個功效和Apache中的HostnameLookups一樣,設為關閉。
    connectionTimeout 為網絡連接超時時間毫秒數。
    maxThreads Tomcat使用線程來處理接收的每個請求。這個值表示Tomcat可創建的最大的線程數,即最大并發數。
    acceptCount是當線程數達到maxThreads后,后續請求會被放入一個等待隊列,這個acceptCount是這個隊列的大小,如果這個隊列也滿了,就直接refuse connection

     

    五、JNDI配置
    [root@slave3 conf]# vi context.xml
    mysql驅動包 :http://mirrors.sohu.com/mysql/Connector-J/mysql-connector-java-5.1.34.zip
    oracle驅動包:http://www.oracle.com/technetwork/cn/articles/oem/jdbc-112010-094555-zhs.html
    tomcat下載地址:http://archive.apache.org/dist/tomcat/tomcat-7/v7.0.56/bin/apache-tomcat-7.0.56.zip
    編輯conf下的context.xml文件在Context模塊插入以下Resource信息
    <Context>
    <Resource name="jdbc/cfgDS"
                  auth="Container"
                  type="javax.sql.DataSource"
                  driverClassName="oracle.jdbc.driver.OracleDriver"
                  url="jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=10.10.5.18)(PORT=1901)))(CONNECT_DATA=(SERVICE_NAME=hccdb)))"
                  username="mpm"
                  password="mpm"
                  maxActive="30"
                  maxIdle="0"
                  maxWait="30000" />
    <Resource name="jdbc/BookDB"
                  auth="Container"
                  driverClassName="com.mysql.jdbc.Driver"
                  type="javax.sql.DataSource" url="jdbc:mysql://10.10.6.77:3306/amdb?characterEncoding=UTF-8"
                  username="root"
                  password="mangocity"
                  maxActive="30"
                  maxIdle="0"
                  maxWait="30000" />
    </Context>


    驗證:
    在WEB-INF/ 下創建  web.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE web-app PUBLIC
          '-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN'  ';
    <web-app>
    <resource-ref>
          <description>DB Connection</description>
          <res-ref-name>jdbc/BookDB</res-ref-name>
          <res-type>javax.sql.DataSource</res-type>
          <res-auth>Container</res-auth>
    </resource-ref>
    </web-app>
  2. 創建jsp文件, index.jsp
    <%@ page language="java" import="java.util.,javax.naming.,java.sql.,javax.sql."pageEncoding="UTF-8"%>
    <%     
        Context ctx = new InitialContext();       
        String strLookup = "java:comp/env/jdbc/BookDB";  
        DataSource ds =(DataSource) ctx.lookup(strLookup); 
        Connection con = ds.getConnection(); 
        if (con != null){ 
            out.print("success"); 
       }else{ 
            out.print("failure"); 
        }        
    %>
 本文由用戶 gww3 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!