java內存調優
『壹』 tomcat 性能調優
java性能優化原則:代碼運算性能 內存回收 應用配置(影響java程序注意原因是垃圾回收)
代碼層優化:避免過多的循環嵌套 調用和復雜邏輯
Tomcat調優主要內容
1.增加最大連接數
2.調整工作模式
3.啟用gzip壓縮
4.調整JVM內存大小
5.作為web伺服器時 與Apache整合或Nginx
6.合理選擇垃圾回收演算法
7.盡量使用較新版的JDK
生產環境實例
<connector p=""
maxThreads="1000"
minSpareThreads="100"
maxSpareThreads="200"
acceptCount="900"
disableUploadTimeout="true"
connectionTimeout="20000"
URIEncoding="UTF-8"
enableLookups="false"
redirectPort="8443"
compression="on"
compressionMinSize="1024"
compressableMimeType="text/html,text/xml,text/css,text/javascript"/>
參數說明:
org.apache.coyote.http11.Http11NioProtocol:調整工作模式為Nio
maxThreads:最大線程數,默認150。增大值避免隊列請求過多,導致響應緩慢。
minSpareThreads:最小空閑線程數
maxSpareThreads:最大空閑線程數,如果超過這個值,會關閉無用的線程。
acceptCount:當處理請求超過此值時,將後來請求放到隊列中等待。
disableUploadTimeout:禁用上傳超時時間
connectionTimeout:連接超時,單位毫秒,0代表不限制
URIEncoding:URI地址編碼使用UTF-8
enableLookups:關閉dns解析,提高響應時間
compression:啟用壓縮功能
compressionMinSize:最小壓縮大小,單位Byte
compressableMimeType:壓縮的文件類型
Tomcat的三種工作模式: Bio、Nio和Apr 工作原理分別為
Bio(Blocking I/O):默認工作模式 阻塞式I/O操作 沒有任何優化技術處理 性能比較低
Nio(New I/O or Non-Blocking):非阻塞式I/O操作 有BIO更好的並發處理性能
Apr(apache portable runtime,apache可移植運行庫):首選工作模式 主要為上層的應用程序提供一個可以跨越多操作系統平台使用的底層支持介面庫
Tomcat利用基於APR庫Tomcat-native來實現操作系統級別控制 提供一種優化技術和非阻塞式I/O操作 大大提高並發處理能力
但是需要安裝APR和Tomcat-native庫
Java性能問題主要來自於jvm jvm GC也比較復雜
1、jvm內存劃分為年輕代(Young Generation)、年老代 Old Generation)、永久代(Permanent Generation)
2、年輕代又分為Eden和Survivor區。Survivor區由FromSpace和ToSpace組成。Eden區佔大容量,Survivor兩個區佔小容量,默認8:2
3、堆內存Heap=年輕代+年老代 非堆內存=永久代
4、堆內存用途:存放的是對象 垃圾收集器就是收集這些對象的 然後根據GC演算法回收
5、非堆內存用途:JVM本身使用 存放一些類型 方法 常量 屬性等
6、年輕代:新生成的對象首選放到年輕代的E區中 當E區滿時 經過GC後 還存活的對象被復制到Survivor區的FromSpace中 如果survivor區滿
會再被復制到survivor區的ToSpace區 如果還有存活的對象 會再被復制到老年代
7、老年代:在年輕代中經過GC後還存活的對象會被復制到老年代中 當老年代空間不足時 jvm會對老年代進行完全的垃圾回收(Full GC)
如果GC後 還是無法存放從survivor區復制過來的對象 就會出現OOM
8、永久代:也稱為方法區 存放靜態類型數據 比如類 方法 屬性等
垃圾回收演算法
1、標記 清除
2、復制
3、標記 整理
垃圾收集器
單線程/多線程收集器
GMS收集器
JAVA_OPTS="-server -Xms1024m -Xmx1536m -XX:PermSize=256m -XX:MaxPermSize=512m -XX:+UseConcMarkSweepGC -XX:+UseParallelGCThreads=8 XX:=80 -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:-PrintGC -XX:-PrintGCDetails -XX:-PrintGCTimeStamps -Xloggc:../logs/gc.log"
參數 描述
-Xms 堆內存初始大小 單位M、G
-Xmx 堆內存最大允許大小 一般不要大於物理內存的80%
-XX:PermSize 非堆內存初始大小 一般應用設置初始化200M 最大1024M就夠了
-XX:MaxPermSize 非堆內存最大允許值
-XX:+UseParallelGCThreads=8 並行收集器線程數 同時有多少個線程進行垃圾回收 一般與CPU數量相等
-XX:+UseParalle101dGC 指定老年代為並行收集
-XX:+UseConcMarkSweepGC CSM收集器
-XX:+ 開啟內存空間壓縮和整理 防止過多內存碎片
-XX:CMSFullGCsBeforeCompaction=0 表示多少次Full GC後開始壓縮和整理 0表示每次Full GC後立即執行壓縮和整理
-XX:=80% 表示老年代內存空間使用80%時開始執行CMS收集 防止過多的Full GC
注意:不是jvm內存設置越大越好 具體還是根據項目對象實際占內存大小而定 可以通過java自帶的分析工具來查看
如果設置過大 會增加回收實際 從而增加暫停應用時間
gzip壓縮作用:節省伺服器流量和提高網站訪問速度 客戶端請求伺服器資源後 伺服器將資源文件壓縮 再返回給客戶端 有客戶端的瀏覽器負責壓縮並瀏覽
Apache和Tomcat結合
由於Tomcat處理靜態文件能力遠遠不足Apache 所有用Apache處理靜態文件 Tomcat負責處理jsp
session會話的保持
TomcatSessionID持久化三種方法
session粘性:通過瀏覽器cookie綁定sessionID 通過sticky模式將同一session請求分片到同一Tomcat上
session復制:tomcat通過廣播形式將session同步到其它Tomcat節點 並且Linux下要手動開啟開放廣播地址 不宜後端節點過多
session保持資料庫(memcache redis):將sessionID保存在共享的資料庫中
OOM異常的幾個原因
老年代內存不足:java.lang.OutOfMemoryError:Javaheapspace
永久代內存不足:java.lang.OutOfMemoryError:PermGenspace
代碼bug 佔用內存無法及時回收
『貳』 Java軟體工程師主要學習哪些課程
第一階段,Java SE基礎:
Java環境搭建、Java流程式控制制語句-for循環、switch選擇判斷、循環嵌套、數組拷貝、多維數組、final關鍵字、構造函數的調用、類的訪問許可權和路徑、面向對象高級特性、Java異常處理、Set,Map,List介面及介面實現類、Java線程、同步阻塞、JavaIO流、文件的操作,復制,讀寫,刪除等。第二階段,JavaWeb:Mysql安裝、管理、創建資料庫、MySQL
UPDATE 查詢、Mysql高級操作、JDBC、JDBC資料庫連接操作,JDBC動態Sql處理、Servlet3.0
網頁重定向、Servlet3.0 新增的註解支持、AJAX、responseText屬性詳解等。第三階段,Java高級框架-SSH:Struts2異常處理、Struts2+Log4j集成、Struts2和JSON實例、Hibernate5、Hibernate集合映射、Hibernate組件映射、Spring4.0、SpringAOP
+ AspectJ框架、Spring 與其它Web框架集成、Spring Hibernate支持等。第四階段,Java高級框架-SSM:SpringMVC、Spring MVC生成JSON數據、MyBatis、MyBatis 環境配置及入門、Mybatis set標簽、Mybatis trim標簽、Shiro、Shiro快速入門教程、Shiro Web應用等。第五階段,SpringBoot+VUE全棧框架:SpringBoot、全局異常處理、過濾器監聽器、EHCache緩存、SpringBoot Quartz定時任務、Vue、Vue.js 安裝、模板語法、計算屬性、事件處理器、Vue.js 自定義指令、Vue.js 路由等第六階段,特色課程:ActiveM環境搭建、生產者和消費者、消息持久化操作、RSA數字加密演算法、Codebar條形碼生成器、zxing二維碼生成器、HighCharts統計圖、Echarts統計圖、網路播放器ckplayer、嵌入式網路播放器,可以瀏覽器和移動端隨意使用第七階段,互聯網框架的高級應用1:分布式服務框架的理解,Dubbo架構設計詳解及其核心要點,框架運行原理分析、SpringData數據訪問、Lucene搜索引擎、Lucene的全文搜索伺服器介紹、索引建立方式、Solr海量數據搜索引擎、Socket網路通信、實現RMI遠程對象通訊、使用JMS消息服務、Kafka分布式消息系統、WebService與Restful
WS等第八階段,互聯網框架的高級應用2:Spring Security安全框架、實現Web應用安全控制、緩存應用與EhCache框架、OSCache與JBossCache框架、MyBatis與Hibernate緩存機制、NoSQL應用與SQL調優、MongoDB
NoSQL資料庫、Redis內存資料庫、實現Redis
Session共享、SQL語句的優化、實現資料庫讀寫分離、WEB應用集群及性能優化、Maven項目管理工具、Web伺服器負載均衡、實現Nginx與Tomcat集群、使用LoadRunner測試工具、性能優化之內存調優、代碼優化與重構的方法等。
對java有興趣的小夥伴們,不妨先從java入門開始!B站上有很多的java教學視頻,從基礎到高級的都有,還挺不錯的,知識點講的很細致,還有完整版的學習路線圖。也可以自己去看看,下載學習試試。
『叄』 java有內存溢出嗎如果有是什麼情況
內存溢出是指應用系統中存在無法回收的內存或使用的內存過多,最終使得程序運行要用到的內存大於虛擬機能提供的頃高最大內存。
所以我們應該明確:存在內存溢出的因不一定導致內存溢出的果。。。
1。JAVA操作文本文件為什麼超過3萬行就雀衡尺內存益處啊?
PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(fileName)));
//PrintWriter out = new PrintWriter(fileName);
//FileOutputStream out = new FileOutputStream(fileName);
while (rs.next()) {
for (int j = 1; j <= totalColumn; j++) {
out.write(rs.getObject(j).toString());
out.write("\t");
}
out.write("\n");
out.flush();
}
}
我在代碼中 寫了 out.flush()用來刷新該流的緩沖; 可是當我的記錄數超過3W時就報了內存益處的問題了,難道JAVA不能邊讀邊寫嗎?還是out這個對象隨著指向的fileName文件的邊大佔用內存也大了嗎??到底怎麼來實現用JAVA寫更多的數據而不內存益處呢
答案是:就在while(rs.next()) 當rs.next()時內存不斷增大,而不是寫流的問題,JAVA的ResultSet真是麻煩,而且ResultSet還不能clone(); 所以記得在做項目的時候,經常要設置:jdbc.setMaxRows(100*10000); //設置能容納100萬行記錄-----這個就是防止內存泄露的哈------------------- 內存中載入的數據量過於龐大,如一次從資料庫取出過多數據;
jdbc.setQueryTimeout(60*30); //設置超時時間是30分鍾
2。java中的內存泄露的情況:長生命周期的對象持有短生命周期對象的引用就很可能發生內存泄露,盡管短生命周期對象已經不再需要,但是因為長生命周期對象持有它的引用而導致不能被回收,這就是java中內存泄露的發生場景,通俗地說,就是程序員可能創建了一個對象,以後一直不再使用這個對象,這個對象卻一直被引用,即這個對象無用但是卻無法被垃圾回收器回收的攔改,這就是java中可能出現內存泄露的情況,例如,緩存系統,我們載入了一個對象放在緩存中(例如放在一個全局map對象中),然後一直不再使用它,這個對象一直被緩存引用,但卻不再被使用。
public class Stack { //長生命周期
private Object[] elements=new Object[10]; //當數組容器中沒有東西時是無用的,但是無法回收~~elements是短生命周期
private int size = 0;
public void push(Object e){
ensureCapacity();
elements[size++] = e;
}
public Object pop(){
if( size == 0)
throw new EmptyStackException();
//這里還是引用了,只是指針變位置變化而已,他確實返回了那個對象,但是他卻沒有斷開那個對象的引用,也就是說有兩個地方會持有這個對象的引用,調用pop的地方,和elements中
return elements[--size];
}
private void ensureCapacity(){
if(elements.length == size){
Object[] oldElements = elements;
elements = new Object[2 * elements.length+1];
System.array(oldElements,0, elements, 0, size);
}
}
}
上面的原理應該很簡單,假如堆棧加了10個元素,然後全部彈出來,雖然堆棧是空的,沒有我們要的東西,但是這是個對象是無法回收的,這個才符合了內存泄露的兩個條件(必要條件):無用,無法回收。
例子1
public class Bad{
public static Stack s=Stack();
static{
s.push(new Object());
s.pop(); //這里有一個對象發生內存泄露
s.push(new Object()); //上面的對象可以被回收了,等於是自愈了,因為引用被覆蓋了
}
}
因為是static,就一直存在到程序退出,但是我們也可以看到它有自愈功能,就是說如果你的Stack最多有100個對象,那麼最多也就只有100個對象無法被回收其實這個應該很容易理解,Stack內部持有100個引用,最壞的情況就是他們都是無用的,因為我們一旦放新的進取,以前的引用自然消失!
內存泄露的另外一種情況:當一個對象被存儲進HashSet集合中以後,就不能修改這個對象中的那些參與計算哈希值的欄位了,否則,對象修改後的哈希值與最初存儲進HashSet集合中時的哈希值就不同了,在這種情況下,即使在contains方法使用該對象的當前引用作為的參數去HashSet集合中檢索對象,也將返回找不到對象的結果,這也會導致無法從HashSet集合中單獨刪除當前對象,造成內存泄露。
這是屬於: 集合類中有對對象的引用,使用完後未清空,使得JVM不能回收;
3。代碼中存在死循環或循環產生過多重復的對象實體;
4。啟動參數內存值設定的過小;
『肆』 懂JAVA的大蝦們,幫幫忙,JVM不釋放內存,為什麼
IBM關於內存泄漏的文章:
1)http://www.ibm.com/developerworks/library/j-leaks/index.html
2)http://www.ibm.com/developerworks/cn/java/l-JavaMemoryLeak/
第一篇結尾有提到預防泄漏的方法:
a)注意集合類(比如 Hashtable 和 Vector);尤其是聲明為 static 的
b)記得移除不再需要的事件/組件監聽器
c)很多類稿宴歷都有引用類型的成員變數;不再需要這些成員變數引祥悉用的鍵搜對象時,把它們設為 null
程序沒有外部調用,把程序停了,系統也不釋放內存?
怎麼可能?
最好代碼能讓大家看看。
『伍』 學習Java為什麼需要理解它的內存機制
不懂Java的內存機制,遇到某些問題磨沒李時就不知道其中的微妙原因,也寫不出好的高並發安全、低內存佔用的程序,也不會JVM的性能調優。理解底層原理有助於理解很多瞎遲東西實察纖現的細節。
『陸』 jvm 內存調優用過哪些工具,jstate 做什麼用的如何 mp 出當前線程狀態
實例一:Waiting to lock 和 Blocked
"RMI TCP Connection(267865)-172.16.5.25" daemon prio=10 tid=0x00007fd508371000 nid=0x55ae waiting for monitor entry [0x00007fd4f8684000]
java.lang.Thread.State: BLOCKED (on object monitor)
at org.apache.log4j.Category.callAppenders(Category.java:201)
- waiting to lock <0x00000000acf4d0c0> (a org.apache.log4j.Logger)
at org.apache.log4j.Category.forcedLog(Category.java:388)
at org.apache.log4j.Category.log(Category.java:853)
at org.apache.commons.logging.impl.Log4JLogger.warn(Log4JLogger.java:234)
at com.tuan.core.common.lang.cache.remote.SpyMemcachedClient.get(SpyMemcachedClient.java:110)
說明:
1)線程狀態是 Blocked,阻塞狀態。說明線程等待資源超時裂悶!
2)「 waiting to lock <0x00000000acf4d0c0>」指,線程在等待給這個 0x00000000acf4d0c0 地址上鎖(英文可肆跡彎描述為:trying to obtain 0x00000000acf4d0c0 lock)。
3)在 mp 日誌里查找字元串 0x00000000acf4d0c0,發現有大量線程都在等待給這個地址上鎖。如果能在日誌里找到誰獲得了這個鎖(如locked < 0x00000000acf4d0c0 >),就可以順藤摸瓜了。
4)「waiting for monitor entry」說明此線程通過 synchronized(obj) {……} 申州告請進入了臨界區,從而進入了下圖1中的「Entry Set」隊列,但該 obj 對應的 monitor 被其他線程擁有,所以本線程在 Entry Set 隊列中等待。
5)第一行里,"RMI TCP Connection(267865)-172.16.5.25"是 Thread Name 。tid指Java Thread id。nid指native線程的id。prio是線程優先順序。[0x00007fd4f8684000]是線程棧起始地址。
實例二:Waiting on condition 和 TIMED_WAITING
"RMI TCP Connection(idle)" daemon prio=10 tid=0x00007fd50834e800 nid=0x56b2 waiting on condition [0x00007fd4f1a59000]
java.lang.Thread.State: TIMED_WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x00000000acd84de8> (a java.util.concurrent.SynchronousQueue$TransferStack)
at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:198)
at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:424)
at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:323)
at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:874)
at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:945)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:907)
at java.lang.Thread.run(Thread.java:662)
說明:
1)「TIMED_WAITING (parking)」中的 timed_waiting 指等待狀態,但這里指定了時間,到達指定的時間後自動退出等待狀態;parking指線程處於掛起中。
2)「waiting on condition」需要與堆棧中的「parking to wait for <0x00000000acd84de8> (a java.util.concurrent.SynchronousQueue$TransferStack)」結合來看。首先,本線程肯定是在等待某個條件的發生,來把自己喚醒。其次,SynchronousQueue 並不是一個隊列,只是線程之間移交信息的機制,當我們把一個元素放入到 SynchronousQueue 中時必須有另一個線程正在等待接受移交的任務,因此這就是本線程在等待的條件。
3)別的就看不出來了。
『柒』 java 虛擬機內存因程序需要已確定在2—4G范圍內,請問怎樣分配該內存較好。請各位大神給出幾套方案!
適合的才是最好的,不要盲目的加參數。
1. 首先呢,建議是把-Xms和-Xmx設置成一致,且設置為2G/4G,記得加-server參數,也就是在啟動的命令行保證如下參數
java-server-Xms2000m-Xmx2000m
2. 上面就完成了JVM的基本配置,建議此時鎮春對該JVM進行壓力測試,並追加JVM的gc參數,分析內存的使用情況。
java-server-Xms2000m-Xmx2000m-Xloggc:$CATALINA_HOME/logs/gc.log
3. 使用HPjmter或jprofile等對JVM的內存回收日誌gc.log進行分析。看內存瓶頸在哪裡,在對應分析調整。春鍵這個性能調優不是隨扒旅巧便調的,盲目的調會有負作用。如果上述軟體不知道的請GOOGLE之。
『捌』 jvm性能調優都做了什麼
JVM是最好的軟體工程之一,它為Java提供了堅實的基礎,許多流行語言如Kotlin、Scala、Clojure、Groovy都使用JVM作為運行基礎。一個專業的Java工程師必須要了解並掌握JVM,接下來就給大家分享Java基礎知識中JVM調優相關知識點。
杭州Java基礎知識學習之JVM調優講解
JVM常見的調優參數包括:
-Xmx:指定java程序的最大堆內存, 使用java -Xmx5000M -version判斷當前系統能分配的最大堆內存;
-Xms:指定最小堆內存, 通常設置成跟最大堆內存一樣,減少GC;
-Xmn:設置年輕代大小。整個堆大小=年輕代大小+年老代大小。所以增大年輕代後,將會減小年老代大小。此值對系統性能影響較大,Sun官方推薦配置為整個堆的3/8;
-Xss:指定線程的最大棧空間, 此參數決定了java函數調用的深度, 值越大調用深度越深, 若值太小則容易出棧溢出錯誤(StackOverflowError);
-XX:PermSize:指定方法區(永久區)的初始值,默認是物理內存的1/64,在Java8永久區移除, 代之的是元數據區,由-XX:MetaspaceSize指定;
-XX:MaxPermSize:指定方法區的最大值, 默認是物理內存的1/4,在java8中由-XX:MaxMetaspaceSize指定元數據區的大小;
-XX:NewRatio=n:年老代與年輕代的比值,-XX:NewRatio=2, 表示年老代與年輕代的比值為2:1;
-XX:SurvivorRatio=n:Eden區與Survivor區的大小比值,-XX:SurvivorRatio=8表示Eden區與Survivor區的大小比值是8:1:1,因為Survivor區有兩個(from, to)。
JVM實質上分為三大塊,年輕代(YoungGen),年老代(Old Memory),及持久代(Perm,在Java8中被取消)。
年輕代大小選擇
響應時間優先的應用:盡可能設大,直到接近系統的最低響應時間限制(根據實際情況選擇)。在此種情況下,年輕代收集發生的頻率也是最小的。同時,減少到達年老代的對象。
吞吐量優先的應用:盡可能的設置大,可能到達Gbit的程度。因為對響應時間沒有要求,垃圾收集可以並行進行,一般適合8CPU以上的應用。
年老代大小選擇
響應時間優先的應用:年老代使用並發收集器,所以其大小需要小心設置,一般要考慮並發會話率和會話持續時間等一些參數。如果堆設置小了,可以會造成內存碎片、高回收頻率以及應用暫停而使用傳統的標記清除方式;如果堆大了,則需要較長的收集時間。最優化的方案,一般需要參考以下數據獲得:並發垃圾收集信息、持久代並發收集次數、傳統GC信息、花在年輕代和年老代回收上的時間比例。
減少年輕代和年老代花費的時間,一般會提高應用的效率。
吞吐量優先的應用:一般吞吐量優先的應用都有一個很大的年輕代和一個較小的年老代。原因是,這樣可以盡可能回收掉大部分短期對象,減少中期的對象,而年老代盡存放長期存活對象。
較小堆引起的碎片問題
因為年老代的並發收集器使用標記、清除演算法,所以不會對堆進行壓縮。當收集器回收時,他會把相鄰的空間進行合並,這樣可以分配給較大的對象。但是,當堆空間較小時,運行一段時間以後,就會出現「碎片」,如果並發收集器找不到足夠的空間,那麼並發收集器將會停止,然後使用傳統的標記、清除方式進行回收。如果出現「碎片」,可能需要進行如下配置:
-XX:+UseCMSCompactAtFullCollection:使用並發收集器時,開啟對年老代的壓縮。
-XX:CMSFullGCsBeforeCompaction=0:上面配置開啟的情況下,這里設置多少次Full GC後,對年老代進行壓縮。
『玖』 java內存溢出是什麼情況
首先先說一下JVM內存結構問題,JVM為兩塊:PermanentSapce和HeapSpace,其中x0dx0aHeap = }。PermantSpace負責保存反射對象,一般不用配置。JVM的Heap區可以通過-X參數來設定。x0dx0a 當一個URL被訪問時,內存申請過程如下:x0dx0aA. JVM會試圖為相關Java對象在Eden中初始化一塊內存區域x0dx0aB. 當Eden空間足夠時,內存申請結束。否則到下一步x0dx0aC. JVM試圖釋放在Eden中所有不活躍的對象(這屬於1或更高級的垃圾回收), 釋放後若Eden空間仍然不足以放入新對象,則試圖將部分Eden中活躍對象放入Survivor區x0dx0aD. Survivor區被用來作為Eden及OLD的中間交換區域,當OLD區空間足夠時,Survivor區的對象會被移到Old區,否洞和消則會被保留在Survivor區x0dx0aE. 當OLD區空間不夠時,JVM會在OLD區進行完全的垃圾收集(0級)x0dx0aF. 完全垃圾收集後,若Survivor及OLD區仍然無法存放從Eden復制過來的部分對象,導致JVM無法在Eden區為新對象創建內存區域,則出現」out of memory錯誤」x0dx0ax0dx0aJVM調優建議:x0dx0ax0dx0ams/mx:定義YOUNG+OLD段的總尺寸,ms為JVM啟動時YOUNG+OLD的內存大小;mx為最大可佔用的YOUNG+OLD內存大小。在用戶生產環境上一般將這兩個值設為相同,以減少運行期間系統在內存申請上所納知花的開銷。x0dx0aNewSize/MaxNewSize:定義YOUNG段的尺寸,NewSize為JVM啟動時YOUNG的內存大小;MaxNewSize為最大可佔用的YOUNG內存大小。在用戶生產環境上一般將這兩個值設為相同,以減少運行期間系統在內存申請上所花的開銷。x0dx0aPermSize/MaxPermSize:定義Perm段的尺寸,PermSize為JVM啟動時Perm的內存大小;MaxPermSize為最大可佔用的Perm內存大小。在用戶生產環境上一般將這兩個值設為相同,以減少運行期間系統在內存申請上所花的開銷。x0dx0aSurvivorRatio:設置Survivor空間和Eden空間的比例x0dx0ax0dx0a內存溢出的可能性x0dx0ax0dx0a1. OLD段溢出x0dx0a這種內存溢出是最常見的情況之一,產生的原因可能是:x0dx0a1) 設置的內存參數過小(ms/mx, NewSize/MaxNewSize)x0dx0a2) 程序問題x0dx0a單個程序持續進行消耗內存的處理,如循環幾千次的字元串處理,對字元串處理應建議使用StringBuffer。此時不會報內存溢出錯,卻會使系統持續垃圾收集,無法處理其它請求,相關問題程序可通過Thread Dump獲取(見系統問題診斷一章)單個程序所申請內存過大,有的程序會申請幾十乃至幾百兆內存,此時JVM也會因無法申請到資源而出現內存溢出,對此首先要找到相關功能,然後交予程序員修改,要找到相關程序,必須在Apache日誌中尋找。x0dx0a當Java對象使用完畢後,其所引用的對象卻沒有銷毀,使得JVM認為他還是活躍的對象而不進行回收,這樣累計佔用了大量內存而無法釋放。由於目前市面上還沒有對系統影響小的內存分析工具,故此時只能和程序員一起定位。x0dx0ax0dx0a2. Perm段溢出x0dx0a通常由於Perm段裝載了大量的Servlet類而導致溢出,目前的解決辦法:x0dx0a1) 將PermSize擴大,一般256M能夠滿足要求x0dx0a2) 若別無選擇,則只能將servlet的路徑加到CLASSPATH中,但一般不建議這么處理x0dx0ax0dx0a3. C Heap溢出x0dx0a系統對C Heap沒有限制,故C Heap發生問題時,Java進程所佔內存會棚配持續增長,直到佔用所有可用系統內存x0dx0ax0dx0a參數說明:x0dx0ax0dx0aJVM 堆內存(heap)設置選項 x0dx0a 參數格式 x0dx0a 說 明 x0dx0a x0dx0a設置新對象生產堆內存(Setting the Newgeneration heap size) x0dx0a -XX:NewSize x0dx0a 通過這個選項可以設置Java新對象生產堆內存。在通常情況下這個選項的數值為1 024的整數倍並且大於1MB。這個值的取值規則為,一般情況下這個值-XX:NewSize是最大堆內存(maximum heap size)的四分之一。增加這個選項值的大小是為了增大較大數量的短生命周期對象 x0dx0ax0dx0a增加Java新對象生產堆內存相當於增加了處理器的數目。並且可以並行地分配內存,但是請注意內存的垃圾回收卻是不可以並行處理的 x0dx0a x0dx0a設置最大新對象生產堆內存(Setting the maximum New generation heap size) x0dx0a -XX:MaxNewSize x0dx0a 通過這個選項可以設置最大Java新對象生產堆內存。通常情況下這個選項的數值為1 024的整數倍並且大於1MB x0dx0ax0dx0a其功用與上面的設置新對象生產堆內存-XX:NewSize相同x0dx0ax0dx0a設置新對象生產堆內存的比例(Setting New heap size ratios) x0dx0a -XX:SurvivorRatio x0dx0a 新對象生產區域通常情況下被分為3個子區域:伊甸園,與兩個殘存對象空間,這兩個空間的大小是相同的。通過用-XX:SurvivorRatio=X選項配置伊甸園與殘存對象空間(Eden/survivor)的大小的比例。你可以試著將這個值設置為8,然後監控、觀察垃圾回收的工作情況x0dx0ax0dx0a設置堆內存池的最大值(Setting maximum heap size) x0dx0a -Xmx x0dx0a 通過這個選項可以要求系統為堆內存池分配內存空間的最大值。通常情況下這個選項的數值為1 024的整數倍並且大於1 MB x0dx0ax0dx0a一般情況下這個值(-Xmx)與最小堆內存(minimum heap size _Xms)相同,以降低垃圾回收的頻度 x0dx0a x0dx0a取消垃圾回收 x0dx0a -Xnoclassgc x0dx0a 這個選項用來取消系統對特定類的垃圾回收。它可以防止當這個類的所有引用丟失之後,這個類仍被引用時不會再一次被重新裝載,因此這個選項將增大系統堆內存的空間 x0dx0a x0dx0a設置棧內存的大小 x0dx0a -Xss x0dx0a 這個選項用來控制本地線程棧的大小,當這個選項被設置的較大(>2MB)時將會在很大程度上降低系統的性能。因此在設置這個值時應該格外小心,調整後要注意觀察系統的性能,不斷調整以期達到最優 x0dx0a x0dx0a最後說一句,你的機器的連接數設置也至關重要,連接的關閉最好把時間設置的少些,那些連接非常耗費資源。也是引起內存泄露的主要原因。
『拾』 Tomcat調優
對於Tomcat的處理耗時較長的問題主要有當時的並發量、session數、內存及內存的回收等幾個方面造成的。出現問題之後就要進行分析了。
1.關於Tomcat的session數目
這個可以直接從Tomcat的web管理界面去查看即可
或者藉助於第三方工具Lambda Probe來查看,它相對於Tomcat自帶的管理稍微多了點功能,但也不多
2.監視Tomcat的內存使用情況
使用JDK自帶的jconsole可以比較明了的看到內存的使用情況,線程的狀態,當前載入的類的總量等
JDK自帶的jvisualvm可以下載插件(如GC等),可以查看更豐富的信息。如果是分析本地的Tomcat的話,還可以進行內存抽樣等,檢查每個類的使用情況
3.列印類的載入情況及對象的回收情況
這個可以通過配置JVM的啟動參數,列印這些信息(到屏幕(默認也會到catalina.log中)或者文件),具體參數如下:
-XX:+PrintGC:輸出形式:[GC 118250K->113543K(130112K), 0.0094143 secs] [Full GC 121376K->10414K(130112K), 0.0650971 secs]
-XX:+PrintGCDetails:輸出形式:[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs] [GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs]
-XX:+PrintGCTimeStamps -XX:+PrintGC:PrintGCTimeStamps可與上面兩個混合使用,輸出形式:11.851: [GC 98328K->93620K(130112K), 0.0082960 secs]
-XX:+:列印每次垃圾回收前,程序未中斷的執行時間。可與上面混合使用。輸出形式:Application time: 0.5291524 seconds
-XX:+PrintGCApplicationStoppedTime:列印垃圾拆蠢回收期間程序暫停的時間。可與上面混合使用。輸出形式:Total time for which application threads were stopped: 0.0468229 seconds
-XX:PrintHeapAtGC: 列印GC前後的詳慶頃細堆棧信息
-Xloggc:filename:與上面幾個配合使用,把相關日誌信息記錄到文件以便分析
-verbose:class 監視載入的類的情況
-verbose:gc 在虛擬機發生內存回收時在輸出設備顯示信息
-verbose:jni 輸出native方法調用的相關情況,一般用於診斷jni調用錯誤信息
4.添加JMS遠程監控
對於部署在區域網內其它機器上的Tomcat,可以打開JMX監控埠,區域網其它機器就可以通過這個埠查看一些常用的參數(但一些比較復雜的功能不支持),同樣是在JVM啟動參數中配置即可,配置如下:
-Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false
-Djava.rmi.server.hostname=192.168.71.38 設置JVM的JMS監譽御陸控監聽的IP地址,主要是為了防止錯誤的監聽成127.0.0.1這個內網地址
-Dcom.sun.management.jmxremote.port=1090 設置JVM的JMS監控的埠
-Dcom.sun.management.jmxremote.ssl=false 設置JVM的JMS監控不實用SSL
-Dcom.sun.management.jmxremote.authenticate=false 設置JVM的JMS監控不需要認證
5.專業點的分析工具有
IBM ISA,JProfiler等,具體監控及分析方式去網上搜索即可。
單個Tomcat的處理性能是有限的,當並發量較大的時候,就需要有部署多套來進行負載均衡了。
集群的關鍵點有以下幾點:
1.引入負載端
軟負載可以使用nginx或者apache來進行,主要是使用一個分發的功能
參考:
http://ajita.iteye.com/blog/1715312(nginx負載)
http://ajita.iteye.com/blog/1717121(apache負載)
2.共享session處理
目前的處理方式有如下幾種:
1).使用Tomcat本身的Session復制功能
參考http://ajita.iteye.com/blog/1715312(Session復制的配置)
方案的有點是配置簡單,缺點是當集群數量較多時,Session復制的時間會比較長,影響響應的效率
2).使用第三方來存放共享Session
目前用的較多的是使用memcached來管理共享Session,藉助於memcached-sesson-manager來進行Tomcat的Session管理
參考http://ajita.iteye.com/blog/1716320(使用MSM管理Tomcat集群session)
3).使用黏性session的策略
對於會話要求不太強(不涉及到計費,失敗了允許重新請求下等)的場合,同一個用戶的session可以由nginx或者apache交給同一個Tomcat來處理,這就是所謂的session sticky策略,目前應用也比較多
參考:http://ajita.iteye.com/blog/1848665(tomcat session sticky)
nginx默認不包含session sticky模塊,需要重新編譯才行(windows下我也不知道怎麼重新編譯)
優點是處理效率高多了,缺點是強會話要求的場合不合適
3.小結
以上是實現集群的要點,其中1和2可以組合使用,具體場景具體分析吧~
Tomcat本身還是運行在JVM上的,通過對JVM參數的調整我們可以使Tomcat擁有更好的性能。針對JVM的優化目前主要在兩個方面:
1.內存調優
內存方式的設置是在catalina.sh中,調整一下JAVA_OPTS變數即可,因為後面的啟動參數會把JAVA_OPTS作為JVM的啟動參數來處理。
具體設置如下:
JAVA_OPTS="$JAVA_OPTS -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4"
其各項參數如下:
-Xmx3550m:設置JVM最大可用內存為3550M。
-Xms3550m:設置JVM促使內存為3550m。此值可以設置與-Xmx相同,以避免每次垃圾回收完成後JVM重新分配內存。
-Xmn2g:設置年輕代大小為2G。整個堆大小=年輕代大小 + 年老代大小 + 持久代大小。持久代一般固定大小為64m,所以增大年輕代後,將會減小年老代大小。此值對系統性能影響較大,Sun官方推薦配置為整個堆的3/8。
-Xss128k:設置每個線程的堆棧大小。JDK5.0以後每個線程堆棧大小為1M,以前每個線程堆棧大小為256K。更具應用的線程所需內存大小進行調整。在相同物理內存下,減小這個值能生成更多的線程。但是操作系統對一個進程內的線程數還是有限制的,不能無限生成,經驗值在3000~5000左右。
-XX:NewRatio=4:設置年輕代(包括Eden和兩個Survivor區)與年老代的比值(除去持久代)。設置為4,則年輕代與年老代所佔比值為1:4,年輕代占整個堆棧的1/5
-XX:SurvivorRatio=4:設置年輕代中Eden區與Survivor區的大小比值。設置為4,則兩個Survivor區與一個Eden區的比值為2:4,一個Survivor區占整個年輕代的1/6
-XX:MaxPermSize=16m:設置持久代大小為16m。
-XX:MaxTenuringThreshold=0:設置垃圾最大年齡。如果設置為0的話,則年輕代對象不經過Survivor區,直接進入年老代。對於年老代比較多的應用,可以提高效率。如果將此值設置為一個較大值,則年輕代對象會在Survivor區進行多次復制,這樣可以增加對象再年輕代的存活時間,增加在年輕代即被回收的概論。
2.垃圾回收策略調優
垃圾回收的設置也是在catalina.sh中,調整JAVA_OPTS變數。
具體設置如下:
JAVA_OPTS="$JAVA_OPTS -Xmx3550m -Xms3550m -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100"
具體的垃圾回收策略及相應策略的各項參數如下:
串列收集器(JDK1.5以前主要的回收方式)
-XX:+UseSerialGC:設置串列收集器
並行收集器(吞吐量優先)
示例:
java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100
-XX:+UseParallelGC:選擇垃圾收集器為並行收集器。此配置僅對年輕代有效。即上述配置下,年輕代使用並發收集,而年老代仍舊使用串列收集。
-XX:ParallelGCThreads=20:配置並行收集器的線程數,即:同時多少個線程一起進行垃圾回收。此值最好配置與處理器數目相等。
-XX:+UseParallelOldGC:配置年老代垃圾收集方式為並行收集。JDK6.0支持對年老代並行收集
-XX:MaxGCPauseMillis=100:設置每次年輕代垃圾回收的最長時間,如果無法滿足此時間,JVM會自動調整年輕代大小,以滿足此值。
-XX:+UseAdaptiveSizePolicy:設置此選項後,並行收集器會自動選擇年輕代區大小和相應的Survivor區比例,以達到目標系統規定的最低相應時間或者收集頻率等,此值建議使用並行收集器時,一直打開。
並發收集器(響應時間優先)
示例:java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC
-XX:+UseConcMarkSweepGC:設置年老代為並發收集。測試中配置這個以後,-XX:NewRatio=4的配置失效了,原因不明。所以,此時年輕代大小最好用-Xmn設置。
-XX:+UseParNewGC: 設置年輕代為並行收集。可與CMS收集同時使用。JDK5.0以上,JVM會根據系統配置自行設置,所以無需再設置此值。
-XX:CMSFullGCsBeforeCompaction:由於並發收集器不對內存空間進行壓縮、整理,所以運行一段時間以後會產生「碎片」,使得運行效率降低。此值設置運行多少次GC以後對內存空間進行壓縮、整理。
-XX:+UseCMSCompactAtFullCollection:打開對年老代的壓縮。可能會影響性能,但是可以消除碎片
3.小結
在內存設置中需要做一下權衡
1)內存越大,一般情況下處理的效率也越高,但同時在做垃圾回收的時候所需要的時間也就越長,在這段時間內的處理效率是必然要受影響的。
2)在大多數的網路文章中都推薦 Xmx和Xms設置為一致,說是避免頻繁的回收,這個在測試的時候沒有看到明顯的效果,內存的佔用情況基本都是鋸齒狀的效果,所以這個還要根據實際情況來定。
Tomcat的Connector是Tomcat接收HTTP請求的關鍵模塊,我們可以配置它來指定IO模式,以及處理通過這個Connector接受到的請求的處理線程數以及其它一些常用的HTTP策略。其主要配置參數如下:
1.指定使用NIO模型來接受HTTP請求
protocol="org.apache.coyote.http11.Http11NioProtocol" 指定使用NIO模型來接受HTTP請求。默認是BlockingIO,配置為protocol="HTTP/1.1"
acceptorThreadCount="2" 使用NIO模型時接收線程的數目
2.指定使用線程池來處理HTTP請求
首先要配置一個線程池來處理請求(與Connector是平級的,多個Connector可以使用同一個線程池來處理請求)
<executor maxThreads="1000" minSpareThreads="50" maxIdleTime="600000"/>
<connector executor="tomcatThreadPool" 指定使用的線程池
3.指定BlockingIO模式下的處理線程數目
maxThreads="150"//Tomcat使用線程來處理接收的每個請求。這個值表示Tomcat可創建的最大的線程數。默認值200。可以根據機器的時期性能和內存大小調整,一般可以在400-500。最大可以在800左右。
minSpareThreads="25"---Tomcat初始化時創建的線程數。默認值4。如果當前沒有空閑線程,且沒有超過maxThreads,一次性創建的空閑線程數量。Tomcat初始化時創建的線程數量也由此值設置。
maxSpareThreads="75"--一旦創建的線程超過這個值,Tomcat就會關閉不再需要的socket線程。默認值50。一旦創建的線程超過此數值,Tomcat會關閉不再需要的線程。線程數可以大致上用 「同時在線人數*每秒用戶操作次數*系統平均操作時間」 來計算。
acceptCount="100"----指定當所有可以使用的處理請求的線程數都被使用時,可以放到處理隊列中的請求數,超過這個數的請求將不予處理。默認值10。如果當前可用線程數為0,則將請求放入處理隊列中。這個值限定了請求隊列的大小,超過這個數值的請求將不予處理。
connectionTimeout="20000" --網路連接超時,默認值20000,單位:毫秒。設置為0表示永不超時,這樣設置有隱患的。通常可設置為30000毫秒。
4.其它常用設置
maxHttpHeaderSize="8192" http請求頭信息的最大程度,超過此長度的部分不予處理。一般8K。
URIEncoding="UTF-8" 指定Tomcat容器的URL編碼格式。
disableUploadTimeout="true" 上傳時是否使用超時機制
enableLookups="false"--是否反查域名,默認值為true。為了提高處理能力,應設置為false
compression="on" 打開壓縮功能
compressionMinSize="10240" 啟用壓縮的輸出內容大小,默認為2KB
noCompressionUserAgents="gozilla, traviata" 對於以下的瀏覽器,不啟用壓縮
compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain" 哪些資源類型需要壓縮
5.小結
關於Tomcat的Nio和ThreadPool,本身的引入就提高了處理的復雜性,所以對於效率的提高有多少,需要實際驗證一下。
6.配置示例
<connector redirectPort="8443"
maxThreads="150"
minSpareThreads="25"
maxSpareThreads="75"
acceptCount="100"
connectionTimeout="20000"
protocol="HTTP/1.1"
maxHttpHeaderSize="8192"
URIEncoding="UTF-8"
disableUploadTimeout="true"
enableLookups="false"
compression="on"
compressionMinSize="10240"
noCompressionUserAgents="gozilla, traviata"
compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain">
...
最後給大家分享Spring系列的學習筆記和面試題,包含spring面試題、spring cloud面試題、spring boot面試題、spring教程筆記、spring boot教程筆記、最新阿里巴巴開發手冊(63頁PDF總結)、2022年Java面試手冊。一共整理了1184頁PDF文檔。私信博主(777)領取,祝大家更上一層樓!!!