UseAdaptiveSizePolicy與CMS垃圾回收同時使用導致的JVM報錯


   系統在灰度環境上變更時發現JVM啟動報錯,詳細檢查JVM配置參數,發現新境了如下配置:

   -XX:+UseAdaptiveSizePolicy和-XX:+UseConcMarkSweepGC

   初步猜想是JVM參數配置的問題,於是通過jmap -heap查看系統堆棧使用情況,如下:

Heap Configuration:  
   MinHeapFreeRatio = 40  
   MaxHeapFreeRatio = 70  
   MaxHeapSize      = 10737418240 (10240.0MB)  
   NewSize          = 2147483648 (2048.0MB)  
   MaxNewSize       = 2147483648 (2048.0MB)  
   OldSize          = 5439488 (5.1875MB)  
   NewRatio         = 2  
   SurvivorRatio    = 4  
   PermSize         = 21757952 (20.75MB)  
   MaxPermSize      = 134217728 (128.0MB)  

Heap Usage:  
unknown generation type:  
   capacity = 0 (0.0MB)  
   used     = 0 (0.0MB)  
   free     = 0 (0.0MB)  
   NaN% used  
unknown generation type:  
   capacity = 0 (0.0MB)  
   used     = 0 (0.0MB)  
   free     = 0 (0.0MB)  
   NaN% used  
Perm Generation:  
   capacity = 60878848 (58.05859375MB)  
   used     = 37927152 (36.17015075683594MB)  
   free     = 22951696 (21.888442993164062MB)  
   62.29939173619054% used 

從打印的堆棧信息上看已發現異常

一、JVM分析

1、源碼查看

  分析jdk的management.cpp代碼,發現在計算堆內存區大小的時候,對commit都進行了累加,但是在max_size沒有定義(無效,從MemoryPool獲取)的情況下,total_max沒有累加,導致commited比max大。

  修復后的代碼見:  http://hg.openjdk.java.net/hsx/hsx25/hotspot/file/a70566600baf/src/share/vm/services/management.cpp的方法JVM_ENTRY中。 

 對比: 
   原來只處理: 

if (!has_undefined_max_size) {  
  total_max += u.max_size();  
}  

修復該問題的方式:增加代碼處理沒有定義init和max的情況  

if (has_undefined_init_size) {  
     total_init = (size_t)-1;  
  }  
if (has_undefined_max_size) {  
      total_max = (size_t)-1;  
  }  


 2、jmap不能獲取數據原因

  jmap出現不能獲取的原因:(UseAdaptiveSizePolicy + CMS同時使用會出現) (該狀況源碼: sun/jvm/hotspot/memory/GenerationFactory.java ):  

try {  
     return (Generation) ctor.instantiateWrapperFor(addr);  
} catch (WrongTypeException e) {  
     return new Generation(addr) {  
     public String name() {  
     return "unknown generation type";  
……  

 二、問題產生原因

    目前確認是jvm的bug,初步確認版本為1.6_u30以上,包括1.7都存在該問題.jdk6.30以下版本還未確認(使用1.6_u25版本后,目前還沒有復現問題)---1.6.30以上到1.7的全部版本已經確認有該問題,jdk8修復,其他版本待驗證

   簡要原因分析請參見: http://blog.csdn.net/axman/article/details/8667351       

   在使用cms算法下,如果開啟參數UseAdaptiveSizePolicy,則每次minor gc后會重新計算eden,from和to的大小,計算過程依據的是gc過程統計的一些數據,計算后的eden+from+to不會超過Xmx,同時from和to一般是不相等(初始化的時候from和to是相等的)。主要問題在於計算完后,如果eden變大,ContiguousSpacePool里面的max_eden_size並沒有被更新,還是最開始時候的值,這樣導致jvm在通過call_special調用java.lang.management. MemoryUsage的構造函數的時候會產生exception,產生exception的原因是eden的committed 大於 eden的max_size,導致返回java.lang.management. MemoryUsage對象失敗,最終導致產生顯示異常。 

三、解決辦法

  可以先設置 –XX:-UseAdaptiveSizePolicy來workaround,JDK的版本:sun jdk出問題后的版本目前看是只有jdk8修復;openjdk是hs25修復。 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM