背景原由:java
記起之前的另外一次也是關於內存的調優分享下數據庫
有個系統平時運行很是穩定運行(沒經歷過大併發考驗),然而在一次活動後,人數併發一上來後,系統開始卡。apache
我按經驗開始調優,在每一個關鍵步驟的加入以下代碼耗時統計進行壓測:ubuntu
long startTime = System.currentTimeMillis(); callRpc(); //這裏好比調用RPC僞代碼,固然還在插入數據庫,中間件地方都加入統計 long costTime = (System.currentTimeMillis() - startTime); //統計600毫秒以上耗時 if (costTime > 600) { logger.warning("callRpc cost time:" + costTime); }
而後去grep日誌, 最後神奇的發現各個地方都有超過600毫秒的地方...tomcat
而後各類定位的誤導...併發
固然最終是解決了,緣由是因爲程序裏使用了大對象致使app
細分析,即便這種狀況深研究也是分不少狀況的性能
問題重現:線程
緣由分析:日誌
因爲系統中使用了大對象,當併發來臨,內存講被吃緊,將有可能引發以下三種狀況
第一種狀況, 系統內存夠用(JVM內存未使用到SWAP內存),但JVM內存不夠,最終致使JVM的頻繁垃圾回收(FGC),嚴重影響性能 (stop the word)
第二種狀況,系統內存不夠,把JVM堆部分用到了SWAP,那麼此時的垃圾回收須要把SWAP的內存換回到系統物理內存再進行JVM的垃圾回收。最大影響,致使每次GC的時間變得好久
第三種狀況, 物理內存不夠用, 大量JVM的堆內存被交換到SWAP後,垃圾回收時,把SWAP內存換回物理內存,但SWAP的內存又不會當即回, 此時能夠觀察到垃圾回收同時swap使用的內存會變大(其它部份內存要交換到SWAP裏)
準備:
ubuntu 1G 4核
先關閉SWAP虛擬空間 sudo swapoff -a
java version "1.7.0_101"
apache-tomcat-8.5.9
設置好Tomcat的JVM內存:
JAVA_OPTS="-Xmx500m -Xms500m -Xmn200m -Xss228k -XX:+UseConcMarkSweepGC -XX:+UseParNewGC"
apache-jmeter-2.13 用於模擬HTTP請求壓測,都是100條線程併發進行壓測
模擬代碼以下
/** * 模擬當系統中使用大對象時,對JVM形成的影響 * * @author 包子(何錦彬). 2017.01.07 * @QQ 277803242 */ @WebServlet("/Test") public class Test extends HttpServlet { private static final long serialVersionUID = 1L; private Logger logger = Logger.getLogger(Test.class.getName()); protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // use java heap 10m byte[] bts = new byte[1024 * 1024 * 10];// 代碼段1 long startTime = System.currentTimeMillis(); // deal try { // 模擬業務花費時間 Thread.sleep(500); } catch (InterruptedException e) { } // 理論上這裏輸出500附近 long costTime = (System.currentTimeMillis() - startTime); if (costTime > 600) { logger.warning("cost time:" + costTime); } Writer out = response.getWriter(); out.append("ok"); }
先模擬正常的狀況:
先註釋掉"代碼段1", 1W個請求下來,基本耗時都在500,一切正常,返回都是在500毫秒附近
垃圾回收狀況,只發生了1次YGC,因此係統正常穩定...
模擬第一種狀況:
放開「代碼段1」,讓每次請求都去堆內存申請10m的堆空間,一樣是1W個請求,返回的平均值已經接近了2S
垃圾回收狀況來看, 已經發生了1966次的FGC了, 在上面耗時158秒
模擬第二種狀況:
把系統的SWAP打開,打開2G的SWAP,swapon -a
調大JVM參數,到1G,讓JVM用到部分SWAP的空間
此時再讓每次請求都去堆內存申請10m的堆空間,一樣是1W個請求,性能已經低於第二種狀況
垃圾回收來看,回收次數是1766次,比第二種狀況發生的次數還要少,但FGC耗費的時間已是212秒,
(雖然多了200m內存也沒差距這麼大,更精確看年輕代同樣的內存,耗時也遠超過)遠超過第二種狀況了
此時垃圾回收詳情:
模擬第三種狀況:
這種狀況和我上一篇提到的相似,若是系統內存不夠用時,系統將KIIL掉內存
總結:
頻繁垃圾回收(FGC),會嚴重影響性能。若是此時用耗時統計去尋找瓶頸,會出現失誤;
如JVM堆用到了SWAP分區,當發生GC:
1,會致使大量SWAP被使用,2,致使每次GC的時間變得好久;
SWAP分區開啓能夠有效防止進程由於內存問題而被系統殺掉;
持續更新留言問題,解答疑問
歡迎關注個人公衆號,專一重現各類線上的BUG
或搜 「包子的實驗室」