《深入理解JVM.2nd》筆記(五):調優案例分析與實戰

文章目錄

    • 概念
    • 案例分析
      • 高性能硬件上的程序部署策略
        • 情景再現1
        • 問題分析1
        • 關于Full GC
        • 使用64位JDK來管理大內存可能遇到問題
        • 建立邏輯集群
        • 使用邏輯集群可能遇到的問題
        • 最后解決方案
      • 集群間同步導致的內存溢出
        • 情景再現2
        • 問題分析2
      • 堆外內存導致的溢出錯誤
        • 情景再現3
        • 問題分析3
      • 外部命令導致系統緩慢
        • 情景再現4
        • 問題分析4
      • 服務器JVM進程崩潰
        • 情景再現5
        • 問題分析5
      • 不恰當數據結構導致內存占用過大
        • 情景再現6
        • 問題分析6
      • 由Windows虛擬內存導致的長時間停頓
        • 情景再現7
        • 問題分析7
    • 實戰:Eclipse運行速度調優
      • 調優前的程序運行狀態
        • 簡單eclipse插件開發:eclipse啟動時間顯示器
      • 升級JDK1.6的性能變化及兼容問題
      • 編譯時間和類加載時間的優化
        • Compile Time
      • 調整內存設置控制垃圾收集頻率
      • 選擇收集器降低延遲

概念

實踐是檢驗真理的唯一標準

案例分析

高性能硬件上的程序部署策略

情景再現1

一個15萬PV/天左右的在線文檔類型網站最近更換了硬件系統,新的硬件為4個CPU、16GB物理內存,操作系統為64位CentOS 5.4, Resin作為Web服務器。

整個服務器暫時沒有部署別的應用,所有硬件資源都可以提供給這訪問量并不算太大的網站使用。管理員為了盡量利用硬件資源選用了64位的JDK 1.5,并通過-Xmx和-Xms參數將Java堆固定在12GB。使用一段時間后發現使用效果并不理想,網站經常不定期出現長時間失去響應的情況。

問題分析1

監控服務器運行狀況后發現網站失去響應是由GC停頓導致的,虛擬機運行在Server模式 ,默認使用吞吐量優先收集器,回收12GB的堆 ,一次Full GC的停頓時間高達14秒。并且由于程序設計的關系,訪問文檔時要把文檔從磁盤提取到內存中,導致內存中出現很多由文檔序列化產生的大對象,這些大對象很多都進入了老年代,沒有在Minor GC中清理掉。

這種情況下即使有12GB的堆,內存也很快被消耗殆盡,由此導致每隔十幾分鐘出現十幾秒的停頓,令網站開發人員和管理員感到很沮喪。

這里先不延伸討論程序代碼問題,程序部署上的主要問題顯然是過大的堆內存進行回收時帶來的長時間的停頓。硬件升級前使用32位系統1.5GB的堆,用戶只感覺到使用網站比較緩慢,但不會發生十分明顯的停頓,因此才考慮升級硬件以提升程序效能,如果重新縮小給Java堆分配的內存,那么硬件上的投資就顯得很浪費。


高性能硬件上部署程序,目前主要有兩種方式:

  • 通過64位JDK來使用大內存。
  • 使用若干個32位虛擬機建立邏輯集群來利用硬件資源。

關于Full GC

此案例中的管理員采用了第一種部署方式。對于用戶交互性強、對停頓時間敏感的系統,可以給Java虛擬機分配超大堆的前提是有把握把應用程序的Full GC頻率控制得足夠低, 至少要低到不會影響用戶使用,譬如十幾個小時乃至一天才出現一次Full GC,這樣可以通過在深夜執行定時任務的方式觸發Full GC甚至自動重啟應用服務器來保持內存可用空間在一個穩定的水平。

控制Full GC頻率的關鍵是看應用中絕大多數對象能否符合“朝生夕滅”的原則,即大多數對象的生存時間不應太長,尤其是不能有成批量的、長生存時間的大對象產生,這樣才能保障老年代空間的穩定。

在大多數網站形式的應用里,主要對象的生存周期都應該是請求級或者頁面級的,會話級和全局級的長生命對象相對很少。只要代碼寫得合理,應當都能實現在超大堆中正常使用而沒有Full GC ,這樣的話,使用超大堆內存時,網站響應速度才會比較有保證。

使用64位JDK來管理大內存可能遇到問題

除此之外, 如果讀者計劃使用64位JDK來管理大內存,還需要考慮下面可能面臨的問題:

  • 內存回收導致的長時間停頓。
  • 現階段 ,64位JDK的性能測試結果普遍低于32位JDK。
  • 需要保證程序足夠穩定,因為這種應用要是產生堆溢出幾乎就無法產生堆轉儲快照(因為要產生十幾GB乃至更大的Dump文件 ),哪怕產生了快照也幾乎無法進行分析。
  • 相同程序在64位JDK消耗的內存一般比32位JDK大 ,這是由于指針膨脹,以及數據類型對齊補白等因素導致的。

建立邏輯集群

上面的問題聽起來有點嚇人,所以現階段不少管理員還是選擇第二種方式:使用若干個32位虛擬機建立邏輯集群來利用硬件資源。具體做法是在一臺物理機器上啟動多個應用服務器進程 ,每個服務器進程分配不同端口 ,然后在前端搭建一個負載均衡器 ,以反向代理的方式來分配訪問請求。讀者不需要太過在意均衡器轉發所消耗的性能,即使使用64位JDK ,許多應用也不止有一臺服務器,因此在許多應用中前端的均衡器總是要存在的。

考慮到在一臺物理機器上建立邏輯集群的目的僅僅是為了盡可能利用硬件資源,并不需要關心狀態保留、熱轉移之類的高可用性需求,也不需要保證每個虛擬機進程有絕對準確的均衡負載,因此使用無Session復制的親合式集群是一個相當不錯的選擇。我們僅僅需要保障集群具備親合性,也就是均衡器按一定的規則算法(一般根據SessionID分配)將一個固定的用戶請求永遠分配到固定的一個集群節點進行處理即可,這樣程序開發階段就基本不用為集群環境做什么特別的考慮了。

使用邏輯集群可能遇到的問題

當然 ,很少有沒有缺點的方案,如果使用邏輯集群的方式來部署程序,可能會遇到下面一些問題:

  • 盡量避免節點競爭全局的資源,最典型的就是磁盤競爭,各個節點如果同時訪問某個磁盤文件的話(尤其是并發寫操作容易出現問題),很容易導致IO異常。
  • 很難最高效率地利用某些資源池,譬如連接池,一般都是在各個節點建立自己獨立的連接池 ,這樣有可能導致一些節點池滿了而另外一些節點仍有較多空余。盡管可以使用集中式的JNDI,但這個有一定復雜性并且可能帶來額外的性能開銷。
  • 各個節點仍然不可避免地受到32位的內存限制,在32位Windows平臺中每個進程只能使用2GB的內存,考慮到堆以外的內存開銷,堆一般最多只能開到1.5GB。在某些Linux或UNIX系統(如Solaris)中 ,可以提升到3GB乃至接近4GB的內存,但32位中仍然受最高4GB(232)內存的限制。
  • 大量使用本地緩存(如大量使用HashMap作為K/V緩存 )的應用 ,在邏輯集群中會造成較大的內存浪費,因為每個邏輯節點上都有一份緩存,這時候可以考慮把本地緩存改為集中式緩存。

最后解決方案

介紹完這兩種部署方式,再重新回到這個案例之中,最后的部署方案調整為

  1. 建立5個32位JDK的邏輯集群,每個進程按2GB內存計算(其中堆固定為1.5GB ),占用了10GB內存。
  2. 另外建立一個Apache服務作為前端均衡代理訪問門戶。
  3. 考慮到用戶對響應速度比較關心,并且文檔服務的主要壓力集中在磁盤和內存訪問,CPU資源敏感度較低,因此改為CMS收集器進行垃圾回收。

部署方式調整后,服務再沒有出現長時間停頓,速度比硬件升級前有較大提升。

集群間同步導致的內存溢出

情景再現2

有一個基于B/S的MIS系統,硬件為兩臺2個CPU、8GB內存的HP小型機,服務器是WebLogic 9.2 ,每臺機器啟動了3個WebLogic實例 ,構成一個6個節點的親合式集群。

由于是親合式集群,節點之間沒有進行Sessurn同步,但是有一些需求要實現部分數據在各個節點間共享。開始這些數據存放在數據庫中,但由于讀寫頻繁競爭很激烈,性能影響較大,后面使用JBossCache構建了 一個全局緩存。

全局緩存啟用后,服務正常使用了一段較長的時間, 但最近卻不定期地出現了多次的內存溢出問題

問題分析2

在內存溢出異常不出現的時候,服務內存回收狀況一直正常,每次內存回收后都能恢復到一個穩定的可用空間,開始懷疑是程序某些不常用的代碼路徑中存在內存泄漏,但管理員反映最近程序并未更新、升級過,也沒有進行什么特別操作。只好讓服務帶著-XX : +HeapDumpOnOutOfMemoryError參數運行了一段時間。在最近一次溢出之后,管理員發回了 heapdump文件,發現里面存在著大量的org.jgroups.protocols.pbcast.NAKACK對象。

JBossCache是基于自家的JGroups進行集群間的數據通信,JGroups使用協議棧的方式來實現收發數據包的各種所需特性自由組合,數據包接收和發送時要經過每層協議棧的up()和down()方法,其中的NAKACK棧用于保障各個包的有效順序及重發。JBossCache協議棧如下圖所示。

在這里插入圖片描述

由于信息有傳輸失敗需要重發的可能性,在確認所有注冊在GMS ( Group Membership Service ) 的節點都收到正確的信息前,發送的信息必須在內存中保留。而此MIS的服務端中有一個負責安全校驗的全局Filter , 每當接收到請求時,均會更新一次最后操作時間,并且將這個時間同步到所有的節點去,使得一個用戶在一段時間內不能在多臺機器上登錄。在服務使用過程中,往往一個頁面會產生數次乃至數十次的請求,因此這個過濾器導致集群各個節點之間網絡交互非常頻繁。當網絡情況不能滿足傳輸要求時,重發數據在內存中不斷堆積,很快就產生了內存溢出

這個案例中的問題,既有JBossCache的缺陷,也有MIS系統實現方式上缺陷。 JBossCache官方的maillist中討論過很多次類似的內存溢出異常問題,據說后續版本也有了改進。而更重要的缺陷是這一類被集群共享的數據要使用類似JBossCache這種集群緩存來同步的話 ,可以允許讀操作頻繁,因為數據在本地內存有一份副本,讀取的動作不會耗費多少資源 ,但不應當有過于頻繁的寫操作,那樣會帶來很大的網絡同步的開銷。

堆外內存導致的溢出錯誤

情景再現3

一個學校的小型項目:基于B/S的電子考試系統,為了實現客戶端能實時地從服務器端接收考試數據 , 系統使用了逆向AJAX技術(也稱為Comet或者Server Side Push) ,選用CometD 1.1.1作為服務端推送框架,服務器是Jetty 7.1.4 ,硬件為一臺普通PC機 , Core i5 CPU , 4GB內存,運行32位Windows操作系統。

測試期間發現服務端不定時拋出內存溢出異常,服務器不一定每次都會出現異常,但假如正式考試時崩潰一次,那估計整場電子考試都會亂套,網站管理員嘗試過把堆開到最大, 而32位系統最多到1.6GB就基本無法再加大了,而且開大了基本沒效果,拋出內存溢出異常好像還更加頻繁了。加入-XX :+HeapDumpOnOutOfMemoryError,居然也沒有任何反應,拋出內存溢出異常時什么文件都沒有產生。無奈之下只好掛著jstat并一直緊盯屏幕,發現GC并不頻繁 ,Eden區、Survivor區、老年代以及永久代內存全部都表示“情緒穩定,壓力不大”, 但就是照樣不停地拋出內存溢出異常,管理員壓力很大。最后 ,在內存溢出后從系統日志中找到異常堆棧,如代碼下面所示。

在這里插入圖片描述

問題分析3

操作系統對每個進程能管理的內存是有限制的,這臺服務器使用的32位 Windows平臺的限制是2GB ,其中劃了1.6GB給Java堆 ,而Direct Memory內存并不算入1.6GB的堆之內,因此它最大也只能在剩余的0.4GB空間中分出一部分。在此應用中導致溢出的關鍵是:垃圾收集進行時,虛擬機雖然會對Direct Memory進行回收,但是Direct Memory卻不能像新生代、老年代那樣,發現空間不足了就通知收集器進行垃圾回收,它只能等待老年代滿了后Full GC , 然后“順便地”幫它清理掉內存的廢棄對象。

否則它只能一直等到拋出內存溢出異常時,先catch掉 ,再在catch塊里面“大喊聲:“System.gc()! ”。要是虛擬機還是不聽 ( 譬如打開了-XX:+DisableExplicitGC開關),那就只能眼睜睜地看著堆中還有許多空閑內存 ,自己卻不得不拋出內存溢出異常了。而本案例中使用的CometD 1.1.1框架,正好有大量 的NIO操作需要使用到Direct Memory內存

從實踐經驗的角度出發,除了Java堆和永久代之外,我們注意到下面這些區域還會占用較多的內存,這里所有的內存總和受到操作系統進程最大內存的限制。

  • Direct Memory:可通過-XX:MaxDirectMemorySize調整大小,內存不足時拋出OutOfMemoryError或者OutOfMemoryError : Direct buffer memory。
  • 線程堆棧:可通過-Xss調整大小,內存不足時拋出StackOverflowError (縱向無法分配, 即無法分配新的棧幀)或者OutOfMemoryError : unable to create new native thread (橫向無法分配 ,即無法建立新的線程)。
  • Socket緩存區:每個Socket連接都Receive和Send兩個緩存區,分別占大約37KB和25KB內存,連接多的話這塊內存占用也比較可觀。如果無法分配,則可能會拋出IOException : Too many open files異常。
  • JNI代碼 :如果代碼中使用JNI調用本地庫,那本地庫使用的內存也不在堆中。
  • 虛擬機和GC:虛擬機、GC的代碼執行也要消耗一定的內存。

外部命令導致系統緩慢

情景再現4

一個數字校園應用系統,運行在一臺4個CPU的Solaris 10操作系統上,中間件為GlassFish服務器。系統在做大并發壓力測試的時候,發現請求響應時間比較慢 ,通過操作系統的mpstat工具發現CPU使用率很高 ,并且系統占用絕大多數的CPU資源的程序并不是應用系統本身。這是個不正常的現象,通常情況下用戶應用的CPU占用率應該占主要地位,才能說明系統是正常工作的。

通過Solaris 10的Dtrace腳本可以查看當前情況下哪些系統調用花費了最多的CPU資源 ,Dtrace運行后發現最消耗CPU資源的竟然是“fork”系統調用。眾所周知,“fork”系統調用 是Linux用來產生新進程的,在Java虛擬機中,用戶編寫的Java代碼最多只有線程的概念,不應當有進程的產生。

問題分析4

這是個非常異常的現象。通過本系統的開發人員,最終找到了答案:每個用戶請求的處 理都需要執行一個外部shell腳本來獲得系統的一些信息。執行這個shell腳本是通過Java的 Runtime.getRuntime().exec()方法來調用的。這種調用方式可以達到目的,但是它在Java 虛擬機中是非常消耗資源的操作,即使外部命令本身能很快執行完畢,頻繁調用時創建進程 的開銷也非常可觀。Java虛擬機執行這個命令的過程是:首先克隆一個和當前虛擬機擁有一樣環境變量的進程,再用這個新的進程去執行外部命令,最后再退出這個進程。如果頻繁執 行這個操作,系統的消耗會很大,不僅是CPU, 內存負擔也很重。

用戶根據建議去掉這個Shell腳本執行的語句,改為使用Java的API去獲取這些信息后, 系統很快恢復了正常。

服務器JVM進程崩潰

情景再現5

一個基于B/S的MIS系統,硬件為兩臺2個CRJ、8GB內存的HP系統,服務器是WebLogic 9.2 。正常運行一段時間后,最近發現在運行期間頻繁出現集群節點的虛擬機進程自動關閉的現象,留下了一個hs_err_pid###.log文件后 ,進程就消失了,兩臺物理機器里的每個節點都出現過進程崩潰的現象。

從系統日志中可以看出, 每個節點的虛擬機進程在崩潰前不久,都發生過大量相同的異常,見代碼如下

在這里插入圖片描述

這是一個遠端斷開連接的異常,通過系統管理員了解到系統最近與一個OA門戶做了集成 ,在MIS系統工作流的待辦事項變化時,要通過Web服務通知0A門戶系統,把待辦事項的變化同步到OA門戶之中。通過SoapU測試了一下同步待辦事項的幾個Web服務,發現調用后竟然需要長達3分鐘才能返回,并且返回結果都是連接中斷。

問題分析5

由于MIS系統的用戶多,待辦事項變化很快,為了不被OA系統速度拖累,使用了異步的方式調用Web服務,但由于兩邊服務速度的完全不對等,時間越長就累積了越多Web服務沒有調用完成,導致在等待的線程和Socket連接越來越多,最終在超過虛擬機的承受能力后使得虛擬機進程崩潰。解決方法:通知OA門戶方修復無法使用的集成接口,并將異步調用改為生產者/消費者模式的消息隊列實現后,系統恢復正常。

不恰當數據結構導致內存占用過大

情景再現6

有一個后臺RPC服務器,使用64位虛擬機,內存配置為-Xms4g -Xmx8g-Xmn1g, 使用ParNew+CMS的收集器組合。平時對外服務的Minor GC時間約在30毫秒以內,完全可以接受。但業務上需要每10分鐘加載一個約80MB的數據文件到內存進行數據分析,這些數據會在內存中形成超過100萬個HashMap<Long,Long>Entry,在這段時間里面Minor GC就會造成超過500毫秒的停頓,對于這個停頓時間就接受不了了,具體情況如下面GC日志所示。

在這里插入圖片描述

問題分析6

觀察這個案例,發現平時的Minor GC時間很短,原因是新生代的絕大部分對象都是可清除的, 在Minor GC之后Eden和Survivor基本上處于完全空閑的狀態。而在分析數據文件期間,800MB的Eden空間很快被填滿從而引發GC ,但Minor GC之后,新生代中絕大部分對象依然是存活的。我們知道ParNew收集器使用的是復制算法,這個算法的高效是建立在大部分對象都“朝生夕滅”的特性上的,如果存活對象過多,把這些對象復制到Survivor并維持這些對象引用的正確就成為一個沉重的負擔,因此導致GC暫停時間明顯變長。

如果不修改程序,僅從GC調優的角度去解決這個問題,可以考慮將Survivor空間去掉(加入參數-XX:SurvivorRatio=65536、 -XX:MaxTenuringThreshold=0或者-XX:+AlwaysTenure ) , 讓新生代中存活的對象在第一次Minor GC后立即進入老年代,等到Major GC的時候再清理它們。這種措施可以治標,但也有很大副作用,治本的方案需要修改程序,因為這里的問題產生的根本原因是用HashMap<Long,Long>結構來存儲數據文件空間效率太低

下面具體分析一下空間效率。在HashMap<Long,Long>結構中,只有Key和Value所存放的兩個長整型數據是有效數據,共16B(2x8B)。這兩個長整型數據包裝成java.lang.Long對象之后,就分別具有8B的MarkWord、8B的Klass指針 ,在加8B存儲數據的long值。在這兩個Long對贏組成Map.Entry之后 ,又多了 16B的對象頭,然后一個8B的next字段和4B的int型的hash字段 ,為了對齊,還必須添加4B的空白填充,最后還有HashMap中對這個Entry的8B的引用 ,這樣增加兩個長整型數字,實際耗費的內存為 (Long(24B)x2)+Entry(32B)+HashMap Ref(8B)=88B,空間效率為16B/88B=18%,實在太低了

由Windows虛擬內存導致的長時間停頓

情景再現7

有一個帶心跳檢測功能的GUI桌面程序,每15秒會發送一次心跳檢測信號,如果對方30秒以內都沒有信號返回,那就認為和對方程序的連接已經斷開。程序上線后發現心跳檢測有誤報的概率,查詢日志發現誤報的原因是程序會偶爾出現間隔約一分鐘左右的時間完全無日志輸出,處于停頓狀態。

因為是桌面程序,所需的內存并不大(-Xmx256m), 所以開始并沒有想到是GC導致的程序停頓,但是加入參數-XX:+PrintGCApplicationStoppedTime -XX:+PrintGCDateStamps -Xloggc:gclog.log后 ,從GC日志文件中確認了停頓確實是由GC導致的,大部分GC時間都控制在100毫秒以內,但偶爾就會出現一次接近1分鐘的GC。
在這里插入圖片描述

從GC日志中找到長時間停頓的具體日志信息(添加了-XX:+PrintReferenceGC參數), 找到的日志片段如下所示。從日志中可以看出,真正執行GC動作的時間不是很長,但從準備開始GC ,到真正開始GC之間所消耗的時間卻占了絕大部分。

在這里插入圖片描述

問題分析7

除GC日志之外,還觀察到這個GUI程序內存變化的一個特點,當它最小化的時候,資源管理中顯示的占用內存大幅度減小,但是虛擬內存則沒有變化,因此懷疑程序在最小化時它的工作內存被自動交換到磁盤的頁面文件之中了,這樣發生GC時就有可能因為恢復頁面文件的操作而導致不正常的GC停頓。

在MSDN上查證后確認了這種猜想,因此,在Java的GUI程序中要避免這種現象,可以加入參數“-Dsun.awt.keepWorkingSetOnMinimize=true”來解決。這個參數在許多AWT的程序上都有應用,例如JDK自帶的Visual VM,用于保證程序在恢復最小化時能夠立即響應。在這個案例中加入該參數后,問題得到解決。

實戰:Eclipse運行速度調優

由于環境相差較大,所以不具體重現實驗,只記錄相關要點

調優前的程序運行狀態

VisualVM的VisualGC插件

在這里插入圖片描述


簡單eclipse插件開發:eclipse啟動時間顯示器

Link

1.下載并安裝jdk和eclipse 這里強調一下: 需要下載Eclipse for RCP and RAP Developers, 否則無法新建Plug-in Development 項目.

2.新建項目 安裝好之后打開eclipse, 點擊 File->NewProject。選擇Plug-in Project,點擊Next。新建一個名為com.developer.showtime的項目,所有參數采用默認值.

3.在com.developer.showtime項目的src下新建一個類: ShowTime,代碼如下:

package com.developer.showtime;import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IStartup;public class ShowTime implements IStartup {public void earlyStartup() {Display.getDefault().syncExec(new Runnable() {public void run(){long eclipseStartTime = Long.parseLong(System.getProperty("eclipse.startTime"));long costTime = System.currentTimeMillis() - eclipseStartTime;Shell shell = Display.getDefault().getActiveShell();String message = "Eclipse start in " + costTime + "ms";MessageDialog.openInformation(shell, "Information", message);}});}
}

4.修改plugin.xml文件如下:

<?xml version="1.0" encoding="UTF-8"?>
<?eclipse version="3.4"?><plugin><extension point="org.eclipse.ui.startup"><startup class="com.developer.showtime.ShowTime"/></extension>
</plugin>

5.試運行

右鍵點擊Run as -> Eclipse Application. 此時會運行一個eclipse, 啟動之后就能顯示啟動所需時間.

6.導出插件.

右鍵Export -> Deployable plug-ins and fragments. 在Directory中輸入需要導出的路徑, 點擊finish后會在該目錄下產生一個plugins的目錄, 里面就是插件包:com.developer.showTime_1.0.0.201110161216.jar. 把這個包復制到eclipse目錄下的plugin目錄下. 然后再啟動eclipse 便可以看到eclipse啟動所花的時間.

在這里插入圖片描述

升級JDK1.6的性能變化及兼容問題

從JDK 1.5升級到1.6并不一定帶來性能的提升。

編譯時間和類加載時間的優化

-Xverify:none禁止掉字節碼驗證過程進行優化


Compile Time

編譯時間是指虛擬機的JIT編譯器(Just In Time Compiler)編譯熱點代碼(Hot Spot Code)的耗時。

我們知道Java語言為了實現跨平臺的特性,Java代碼編譯出來后形成的Class文件中存儲的是字節碼(ByteCode),虛擬機通過解釋方式執行字節碼命令,比起C/C++編譯成本地二進制代碼來說,速度要慢不少

為了解決程序解釋執行的速度問題, JDK 1.2以后,虛擬機內置了兩個運行時編譯器1 ,如果一段Java方法被調用次數達到一定程度,就會被判定為熱代碼交給JIT編譯器即時編譯為本地代碼,提高運行速度(這就是HotSpot虛擬機名字的由來 )。

甚至有可能在運行期動態編譯比C/C++的編譯期靜態譯編出來的代碼更優秀,因為運行期可以收集很多編譯器無法知道的信息,甚至可以采用一些很激進的優化手段,在優化條件不成立的時候再逆優化退回來。所以Java程序只要代碼沒有問題(主要是泄漏問題,如內存泄漏、連接泄漏),隨著代碼被編譯得越來越徹底,運行速度應當是越運行越快的。

Java的運行期編譯最大的缺點就是它進行編譯需要消耗程序正常的運行時間,這也就是上面所說的“編譯時間”。


虛擬機提供了一個參數-Xint禁止編譯器運作,強制虛擬機對字節碼采用純解釋方式執行。

但這樣的優化效果中看不中用


與解釋執行相對應的另一方面,虛擬機還有力度更強的編譯器:當虛擬機運行在-client 模式的時候,使用的是一個代號為C1的輕量級編譯器,另外還有一個代號為C2的相對重量級的編譯器能提供更多的優化措施。

如果使用-server模夫的虛擬機啟動Eclipse將會使用到C2 編譯器 ,這時從VisualGC可以看到啟動過程中虛擬機使用了超過15秒的時間去進行代碼編譯。如果讀者的工作習慣是長時間不關閉Eclipse的話 ,C2編譯器所消耗的額外編譯時間最終還是會在運行速度的提升之中賺回來,這樣使用-server模式也是一個不錯的選擇。

調整內存設置控制垃圾收集頻率

可通過以下參數要求虛擬機生成GC日志:

  • -XX:+PrintGCTimeStamps 打印GC停頓時間
  • -XX:+PrintGCDetails 打印GC詳細信息
  • -verbose:gc 打印GC信息,輸出內容已被前一個參數包括,可以不寫
  • -Xloggc:gc.log

Full GC大多數是由于老年代容量擴展而導致的,由永久代空間擴展而導致的也有一部分

-Xms/-Xmx
-XX:PermSize/-XX:MaxPermSize

上面參數將老年代和永久代的容量固定下來,避免運行時自動擴展


-XX:+DisableExplicitGC屏蔽掉System.gc()顯示觸發的GC

選擇收集器降低延遲

一邊編譯,一邊繼續其它編碼工作

CMS是最符合這情景的收集器

-XX:+UseConcMarkSweepGC
-XX:+UseParNewGC

(ParNew收集器是使用CMS收集器后的默認新生代收集器,寫上僅是為了配置更加清晰),要求虛擬機在新生代和老年代分別使用ParNew和CMS收集器進行垃圾回收。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/445696.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/445696.shtml
英文地址,請注明出處:http://en.pswp.cn/news/445696.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

計算機課是一體化教學嗎,計算機基礎課程理實一體化教學模式

計算機基礎課程理實一體化教學模式摘要:“大學計算機基礎”是高職人材培養各專業計算機技術應用的基礎。本文圍繞這一問題,就如何培養學生更好地利用計算機去解決專業領域及日常事務中的問題,如何提高學生利用信息技術解決專業領域問題的能力和意識進行探討。對教學中推進理實一…

Java開發常見面試題詳解(并發,JVM)

預覽 并發 問題詳解請談談你對volatile的理解linkCAS你知道嗎&#xff1f;link原子類Atomiclnteger的ABA問題談談?原子更新引用知道嗎&#xff1f;link我們知道ArrayList是線程不安全&#xff0c;請編碼寫一個不安全的案例并給出解決方案link公平鎖/非公平鎖/可重入鎖/遞歸鎖…

計算機組網配置,計算機組網技術與配置教案..doc

計算機組網技術與配置教案.第一節課課程名稱第1章 計算機組網技術基礎學時2課程內容1.1、計算機網絡介紹&#xff0c;局域網概念&#xff0c;雙絞線和網絡傳輸介質&#xff0c;組網軟硬件具體介紹教學目的掌握計算機網絡的一般概念掌握局域網的定義了解網絡軟硬件組成了解傳輸介…

怎樣恢復計算機管理員身份,電腦高手必備:2招教你找回Windows管理員權限?

原標題&#xff1a;電腦高手必備&#xff1a;2招教你找回Windows管理員權限&#xff1f;昨晚有個小伙伴提問有關Windows賬戶信息的問題&#xff0c;雖然描述上有些籠統吧&#xff0c;但根據小編多年的經驗猜測(此處是得意臉)&#xff0c;不是某些安全軟件把當前賬戶的管理員模式…

K12計算機科學標準,計算機科學新主張(K12基礎教育) 翻譯.pptx

《計算機科學新主張(K12基礎教育) 翻譯.pptx》由會員分享&#xff0c;可在線閱讀&#xff0c;更多相關《計算機科學新主張(K12基礎教育) 翻譯.pptx(26頁珍藏版)》請在人人文庫網上搜索。1、計算機與軟件科學正在改變一切,but the majority of schools dont teach computer scie…

樓主考南師計算機學碩,【圖片】2019南師大新傳學碩考研經驗貼【南京師范大學研究生吧】_百度貼吧...

該樓層疑似違規已被系統折疊 隱藏此樓查看此樓第二階段&#xff1a;7月—8月我個人認為這一階段是在整個專業課復習過程中相對來說最重要的。因為暑假不用上課不用寫作業&#xff0c;基本沒有任何干擾&#xff0c;可以全心全意的投入復習當中。復習的地點大家隨意&#xff0c;我…

計算機中丟失mpr.dll,mprmsg.dll

mprmsg.dll是一款電腦系統缺失修復文件&#xff0c;該文件是很多程序運行的基礎&#xff0c;丟失后會報錯&#xff0c;同時某些時候會發生文件誤刪導致丟失&#xff0c;這時只要下載該文件進行修復即可。軟件介紹mprmsg.dll官方版是一款小巧實用的電腦操作系統專用應用程序擴展…

計算機分類及在信息社會中的應用,計算機在信息社會中的應用.doc

計算機在信息社會中的應用PAGE 11武漢市事業單位工人技能鑒定 技師論文課題名稱 計算機在信息社會中的應用 學生姓名 工 種 工作單位 指導老師 完 成 時 間&#xff1a; 2013年 月 日目 錄TOC \o "1-3" \h \u HYPERLINK \l _Toc18761 一、 前言 PAGEREF _Toc18761 2 …

ajax獲取qq音樂源碼,ajax請求QQ音樂

搜索歌曲function go() {var val document.getElementById("name").value;let url ‘https://c.y.qq.com/soso/fcgi-bin/search_for_qq_cp?g_tk5381&uin0&formatjsonp&inCharsetutf-8&outCharsetutf-8&notice0&platformh5&needNewCod…

Java開發常見面試題詳解(LockSupport,AQS,Spring循環依賴,Redis)

總覽 問題詳解String.intern()的作用linkLeetCode的Two Sum題link什么是可重入鎖&#xff1f;link談談LockSupportlink談談AQSlinkSpring的AOP順序linkSpring的循環依賴linkRedis各基本類型應用場景linkRedis分布式鎖linkRedis內存配置及內存淘汰策略link實現LRU算法link ---…

構造與析構(C++)

2.2 構造與析構2.2.1 構造函數2.2.2 缺省構造函數2.2.3 構造函數的重載2.2.4 類型轉換構造函數2.2.5 拷貝構造函數 2.2 構造與析構 2.2.1 構造函數 構造函數(constructor)是與類同名的特殊成員函數&#xff0c;主要用來初始化對象的數據成員。 像上一個例子&#xff0c;初始…

王者服務器維護什么時間結束s19,王者榮耀S19賽季什么時候結束 S19賽季結束時間...

王者榮耀S19賽季什么時候結束?王者榮耀S19賽季結束時間可能很多小伙伴都不是很了解。很快這個賽季就要結束了&#xff0c;還沒有達到自己滿意段位的玩家要抓緊時間上分了&#xff0c;一起看看S19賽季什么時候結束吧。S19賽季結束時間應該在6月底&#xff0c;根據以往的時間推算…

惠普服務器查詢ilo信息,Hp服務器iLO IML硬件日志收集與遠程巡檢

惠普服務器的iLO模塊&#xff0c;可用于遠程控制服務器電源、開啟遠程控制臺、檢查服務器健康狀態等&#xff0c;其中IML( Integrated Management Log )是排查硬件故障的重要手段&#xff0c;這套小程序就是用來批量收集Hp服務器的IML日志&#xff0c;可寫入本地文件并以郵件形…

微博安全是一個系統問題包括服務器安全,應用安全開發注意事項

新浪安全部門一直致力于推動開放平臺上的產品安全&#xff0c;使微博應用擁有更好的用戶體驗和具備更安全的功能。從目前的情況來看&#xff0c;我們發現部分應用存在下面幾種常見的安全漏洞或缺陷&#xff0c;這些安全漏洞除了對應用本身帶來影響外&#xff0c;也會給用戶帶來…

LeetCode - Easy - 696. Count Binary Substrings

Topic String Description https://leetcode.com/problems/count-binary-substrings/ Give a string s, count the number of non-empty (contiguous) substrings that have the same number of 0’s and 1’s, and all the 0’s and all the 1’s in these substrings are…

MySQL優化學習筆記

----一、MySQL架構介紹-01_課程簡介02_MySQL簡介03_RPM安裝04_ROOT密碼設置和開機自啟動05_安裝位置06_修改字符集07_MySQL配置文件08_MySQL邏輯架構簡介09_存儲引擎簡介-二、索引優化分析-10_SQL性能下降原因11_SQL執行加載順序12_七種JOIN理論13_七種JOIN的SQL編寫14_索引是什…

回溯算法學習筆記

學習資料來源 代碼隨想錄 - 關于回溯算法&#xff0c;你該了解這些&#xff01; 什么是回溯法 回溯&#xff08;backtracking&#xff09;法又稱回溯搜索法&#xff0c;它是一種搜索的方式。 回溯法不容易&#xff0c;但回溯法就是暴力解法。 回溯與遞歸形影不離。 backtra…

Java中int[]與Integer[]相互轉化的方法

傳統方法 //Convert int[] to Integer[] public static Integer[] toObject(int[] intArray) {Integer[] result new Integer[intArray.length];for (int i 0; i < intArray.length; i) {result[i] Integer.valueOf(intArray[i]);}return result; }//Convert Integer[] …

《UNIX環境高級編程 3rd》筆記(1 / 21):UNIX基礎知識

文章目錄引言UNIX體系結構登錄登錄名shell文件和目錄文件系統文件名路徑名工作目錄起始目錄輸入和輸出文件描述符標準輸入、標準輸出和標準錯誤不帶緩沖的IO標準IO程序和進程程序進程和進程ID進程控制線程和線程ID出錯處理出錯恢復用戶標識用戶ID組ID附屬組ID信號時間值系統調用…

《集體智慧編程》筆記(1 / 12):集體智慧導言

文章目錄什么是集體智慧什么是機器學習機器學習的局限性真實生活中的例子學習型算法的其他用途小結Netflix, Google都適用了先進算法&#xff0c;將來自不同人群的數據加以組合&#xff0c;進而得出新的結論&#xff0c;并創造新的商機。 更多類似例子&#xff1a; 約會網站希…