极速11选5
   
 
WEB Server
  當前位置:首頁 > 技術支持 > WEB Server
如何在高性能服務器上進行JVM調優?
發布時間:2017-11-21 瀏覽:1344次
  


极速11选5 www.oeikkj.tw 為了充分利用高性能服務器的硬件資源,有兩種JVM調優方案,它們都有各自的優缺點,需要根據具體的情況進行選擇。

1. 采用64位操作系統,并為JVM分配大內存

我們知道,如果JVM中堆內存太小,那么就會頻繁地發生垃圾回收,而垃圾回收都會伴隨不同程度的程序停頓,因此,如果擴大堆內存的話可以減少垃圾回收的頻率,從而避免程序的停頓。

因此,人們自然而然想到擴大內存容量。而32位操作系統理論上最大只支持4G內存,64位操作系統最大能支持128G內存,因此我們可以使用64位操作系統,并使用64位JVM,并為JVM分配更大的堆內存。但問題也隨之而來。

堆內存變大后,雖然垃圾收集的頻率減少了,但每次垃圾回收的時間變長。如果對內存為14G,那么每次Full GC將長達數十秒。如果Full GC頻繁發生,那么對于一個網站來說是無法忍受的。

因此,對于使用大內存的程序來說,一定要減少Full GC的頻率,如果每天只有一兩次Full GC,而且發生在半夜, 那完全可以接受。

要減少Full GC的頻率,就要盡量避免太多對象進入老年代,可以有以下做法:

  • 確保對象都是“朝生夕死”的 
    一個對象使用完后應盡快讓他失效,然后盡快在新生代中被Minor GC回收掉,盡量避免對象在新生代中停留太長時間。
  • 提高大對象直接進入老年代的門檻 
    通過設置參數-XX:PretrnureSizeThreshold來提高大對象的門檻,盡量讓對象都先進入新生代,然后盡快被Minor GC回收掉,而不要直接進入老年代。 

注意:使用64位JDK的注意點

  1. 64位JDK支持更大的堆內存,但更大的堆內存會導致一次垃圾回收時間過長。
  2. 現階段,64位JDK的性能普遍比32位JDK低。
  3. 堆內存過大無法在發生內存溢出時生成內存快照 
    若將堆內存設為10G,那么當堆內存溢出時就要生成10G的大文件,這基本上是不可能的。
  4. 相同程序,64位JDK要比32位JDK消耗更大的內存 

2. 使用32位JVM集群

針對于64位JDK種種弊端,我們更多選擇使用32位JDK集群來充分利用高性能機器的硬件資源。

如何實現?

在一臺服務器上運行多個服務器程序,這些程序都運行在32位的JDK上。然后再運行個服務器作為反向代理服務器,由它來實現負載均衡。 
由于32位JDK最多支持2G內存,因此每個虛擬結點的堆內存可以分配1.6G,一共運行10個虛擬結點的話,這臺物理服務器可以擁有16G的堆內存。 

有啥弊端?

  1. 多個虛擬節點競爭共享資源時容易出現問題 
    如多個虛擬節點共同競爭IO操作,很可能會引起IO異常。
  2. 很難高效地使用資源池 
    如果每個虛擬節點使用各自的資源池,那么無法實現各個資源池的負載均衡。如果使用集中式資源池,那么又存在競爭的問題。
  3. 每個虛擬節點最大內存為2G

別忘了直接內存也可能導致內存溢出!

問題描述

有個小型網站,使用32位JDK,堆1.6G。運行期間發現老是出現內存溢出。為了判斷是否是堆內存溢出,在程序運行前添加參數:-XX:+HeapDumpOnOutOfMemeryError(添加這個參數后當堆內存溢出時就會輸出異常日至)。但當再次發生內存溢出時,沒有生成相關異常日志。從而可以判定,不是堆內存發生溢出。 

問題分析

我們可以發現,在32位JDK中,將1.6G分配給了堆,還有一部分分配給了JVM的其它內存,只有少于0.4G的內存為非JVM內存。我們知道,如果使用了NIO,那么JVM會在JVM內存之外分配內存空間,這部分內存也叫“直接內存”。因此,如果程序中使用了NIO,那么就要小心“直接內存”不足時發生內存溢出異常了! 

直接內存的垃圾回收過程

直接內存雖然不是JVM內存空間,但它的垃圾回收也有JVM負責。直接內存的垃圾回收發生在Full GC時,只有當老年代內存滿時,垃圾收集器才會順便收集一下直接內存中的垃圾。 
如果直接內存已滿,但老年代沒滿,這時直接內存先是拋出異常,相應的catch塊中調用System.gc()。由于System.gc()只是建議JVM回收,JVM可能不馬上回收內存,那么這時直接內存就拋出內存溢出異常,使得程序終止。

JVM崩潰的原因

當內存溢出時,JVM僅僅會終止當前運行的程序,那么什么時候JVM會崩潰呢? 

什么是異步請求?

我們知道,Web服務器和客戶端采用HTTP通信,而HTTP底層采用TCP通信。異步通信就是當客戶端向服務器發送一個HTTP請求后,將這個請求的TCP連接委托給其它線程,然后它轉而做別的事,那條被委托的線程保持TCP連接,等待服務器的回信。當收到服務器回信后,再將收到的數據轉交給剛才的線程。這個過程就是異步通信過程。 

異步請求如何造成JVM崩潰?

如果一個Web應用使用了較多的異步請求(AJAX),每次主線程發送完請求后都將TCP連接交給一條新的線程去等待服務器回信,那么如果網絡不流暢時,這些受委托的線程遲遲等不到服務器的回信,因此保持著TCP連接。當TCP連接過多時,超過JVM的承受能力,JVM就發生崩潰。

如何處理大對象?

大對象對于JVM來說是個噩耗。如果對象過大,當前新生代的剩余空間裝不下它,那么就需要使用分配擔?;?,將當前新生代的對象都復制到老年代中,給大對象騰出空間。分配擔保涉及到大量的復制,因此效率很低。

那么,如果將大對象直接放入老年代,雖然避免了分配擔保過程,但該對象只有當Full GC時才能被回收,而Full GC的代價是高昂的。如果大對象過多時,老年代很快就裝滿了,這時就需要進行Full GC,如果Full GC頻率過高,程序就會變得很卡。

因此,對于大對象,有如下幾種處理方法: 
1. 在寫程序的時候盡量避免大對象 
從源頭降低大對象的出現,盡量選擇空間利用率較高的數據結構存儲。 
2. 盡量縮短大對象的有效時間 
對象用完后盡快讓它失效,好讓垃圾收集器盡快將他回收,避免因在新生代呆的時間過長而進入老年代。

 
 
  极速11选5  
 
 
版權所有 © 2005-2019 安徽省艾佳信息技術有限公司 皖ICP備06002923號 皖B2-20060015
地址:安徽省合肥市高新區天元路1號留學人員創業園1號樓205 電話:0551-64935878 郵箱:[email protected]