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修复。

时间: 2024-12-23 02:50:57

UseAdaptiveSizePolicy与CMS垃圾回收同时使用导致的JVM报错的相关文章

CMS垃圾回收机制

详解CMS垃圾回收机制 原创不易,未经允许,不得转载~~~ 什么是CMS? Concurrent Mark Sweep. 看名字就知道,CMS是一款并发.使用标记-清除算法的gc. CMS是针对老年代进行回收的GC. CMS有什么用? CMS以获取最小停顿时间为目的. 在一些对响应时间有很高要求的应用或网站中,用户程序不能有长时间的停顿,CMS 可以用于此场景. CMS如何执行?  总体来说CMS的执行过程可以分为以下几个阶段: 3.1 初始标记(STW) 3.2 并发标记 3.3 并发预清理

备份链中断导致差异备份报错案例

原文:备份链中断导致差异备份报错案例 最近一台SQL Server服务器部署SQL Server Backup后,发现每晚的差异备份老是失败,报如下错误: Msg 3035, Level 16, State 1, Line 1 无法执行数据库"xxxx" 的差异备份,因为不存在当前数据库备份.请去掉WITH DIFFERENTIAL 选项后重新发出BACKUP DATABASE 以执行数据库的完整备份. Msg 3013, Level 16, State 1, Line 1 BACKU

关于MySql升级JDBC架包导致时区问题报错(The server time zone value '?й???????' is unrecognized or represents more than one time zone)

报错信息: The server time zone value '?й???????' is unrecognized or represents more than one time zone. You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want

详解CMS垃圾回收机制

原创不易,未经允许,不得转载~~~ 什么是CMS? Concurrent Mark Sweep. 看名字就知道,CMS是一款并发.使用标记-清除算法的gc. CMS是针对老年代进行回收的GC. CMS有什么用? CMS以获取最小停顿时间为目的. 在一些对响应时间有很高要求的应用或网站中,用户程序不能有长时间的停顿,CMS 可以用于此场景. CMS如何执行?  总体来说CMS的执行过程可以分为以下几个阶段: 3.1 初始标记(STW) 3.2 并发标记 3.3 并发预清理 3.4 重标记(STW)

了解 CMS 垃圾回收日志

在CMS GC 时,使用参数-XX:+PrintGCDetails 和 -XX:+PrintGCTimeStamps 会输出很多日志信息,了解这些信息可以帮我们更好的调整参数,以获得更高的性能. 我们来看下在JDK1.4.2_10 中CMS GC日志示例: 39.910: [GC 39.910: [ParNew: 261760K->0K(261952K), 0.2314667 secs] 262017K->26386K(1048384K), 0.2318679 secs] 新生代使用 (Par

气死人不偿命,Q_OBJECT导致的C++报错,而且还看不明白

为了代码可以同时适应VC++和MingW编译器,我改动了我的代码,变成: #ifdef _MSC_VER #pragma comment(lib, "crypt32.lib") // Link OK,Linux 也要附带这两个库,格式是 -lcrypt32 -lws2_32 #pragma comment(lib, "ws2_32.lib") // Link OK //#pragma comment(lib, "dnsapi.lib") // 没

Sql Server 因为触发器问题导致数据库更新报错“在触发器执行过程中引发了错误,批处理已中止”的问题处理

在维护一个非常旧的项目时,由于该项目版本已经非常老了,而且在客户现场运行的非常稳定,更要命的是本人目前没有找到该项目的代码,为了处理一个新的需求而且还不能修改程序代码,于是决定从数据库入手,毕竟该项目数据库的脚本还是可以操作的,那就在数据流的必经之路上拦截数据处理业务就是了,于是决定在一张业务表上加一个触发器,关于触发器的基础这里就不多说了,网上一搜一大堆,其实就是一张表的数据行被操作以后会针对被操作的数据行执行一段存储过程脚本,只不过这个存储过程比较特殊罢了,是专门侦听对表的操作然后由系统调用

191016 Linux中python2升级到python3导致yum命令报错

因为python2到python3的升级,导致使用yum相关的命令时报错: 报错一: command not found... 方案:修改/usr/bin/yum文件的第一行,将结尾的python改成python27(或python2.7),请自行尝试,修改后能查询yum版本即可: 报错二:cannot retrieve matalink for repository:epel/x86... 方案:sed -i ‘s#https://#http://#g' /etc/yum.repos.d/ep

Oracle数据库误删文件导致rman备份报错RMAN-06169解决办法

可能是误删文件导致在使用rman备份时候出现以下提示 RMAN-06169: could not read file header for datafile 15 error reason 1 解决办法 查看数据15文件是什么 SQL> select file#,name from v$datafile; 出现一个/MISSING00015的文件 看来是MISSING00006文件,不是系统,也不是用户的数据. 看MISSING00006基于那个表空间,然后删除该表空间    SQL> sel