标签:
系统在灰度环境上变更时发现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修复。
UseAdaptiveSizePolicy与CMS垃圾回收同时使用导致的JVM报错
标签:
原文地址:http://www.cnblogs.com/moonandstar08/p/5751175.html