[讨论] 奇怪的OOM

muzixinly 2012-07-18

在测试机上做压测,发现不同的机器上gc情况很不一致,多次压测排查后发现是JVM版本不一致导致的,
一个Openjdk,参数为
java version "1.6.0_22"
OpenJDK Runtime Environment (IcedTea6 1.10.6)
OpenJDK 64-Bit Server VM (build 20.0-b11, mixed mode)


另一个OracleJdk,参数
java version "1.6.0_27"
Java(TM) SE Runtime Environment (build 1.6.0_27-b07)
Java HotSpot(TM) 64-Bit Server VM (build 20.2-b06, mixed mode),

测试机系统是rhel5-x86_64,硬件配置是一样的
gc参数:java -Xms6g -Xmx6g -Xmn1g -XX:PermSize=128m -XX:MaxPermSize=128m,用默认的垃圾回收策略
经过长时间的运行(24小时),Hotspot使用old区1.2g,而OpenJdk VM使用old区4.9g,导致oom。

 

(1)初步怀疑是默认的gc策略不同,知道OracleJdk默认的回收算法,鉴于OpenJdk是OracleJdk的开源版本,觉得也应该是一致的,但不确定,用java自带的工具,jinfo穷举,jinfo -flag UseParallelGC pid,输出-XX:+UseParallelGC

确定OracleJdk和Openjdk上默认的回收算法一致,都是UseParallelGC,且-XX:ParallelGCThreads=10。为了排除JDK以外的环境差异,在原本跑OpenJDK6b22的机器上装上用的Oracle JDK版本,oom消失。

(2)看了OpenJdk的官方介绍,两种jdk在版本接近时,性能也比较接近,且同样的情况下,OracleJdk的bug相对OpenJdk更少。猜想会不会正好在两个版本间,修复了某些bug,导致最终的性能有较大差距,遂上java官网,查找bug列表,结果没有找到按版本列出的bug列表。R大回复,HotSpot 20.x上确实有个bug会影响到GC行为,不过那个bug在官方的6u27上还没修,要到6u32才修。这个可能性也可以排除。

(3)写了个测试程序,在两个vm上执行,在不指定任何参数时,java  -cp . GcTest,内存的消耗是接近的
OracleJdk:Memory: used 2051.8M free 35.0M total 2086.9M max 2668.5M
OpenJdk:Memory: used 2051.7M free 30.7M total 2082.4M max 2668.5M

指定参数后:java -Xmx200m -Xms200m -Xmn30m -XX:+PrintGCDetails -Xloggc:gc.log -cp . GcTest
消耗的内存仍然接近,java程序如下:
public class GcTest {
        private static String megabyteString(long bytes) {
                return String.format("%.1f", ((float) bytes) / 1024 / 1024);
        }
        private static void printUsedMemory() {
                Runtime run = Runtime.getRuntime();
                long free = run.freeMemory();
                long total = run.totalMemory();
                long max = run.maxMemory();
                long used = total - free;
                System.out.println("Memory: used " + megabyteString(used) + "M" + " free " + megabyteString(free) + "M" + " total "
                                + megabyteString(total) + "M" + " max " + megabyteString(max) + "M");
        }
        public static void main(String[] args) {
                GcTest test = new GcTest();
                for(int i = 0; i < 5000; i++) {
                     test.allocateMem();
                }
                printUsedMemory();
        }
        public void allocateMem() {
                byte[] used = new byte[50 * 1024 * 1024];
        }

 

彻底懵了,请各位赐教。

chong_zh 2012-07-19
也许open的那套测试系统对象数确实多很多呢,会不会恰好业务load有不同使得两套系统状态出现这么大的差别
muzixinly 2012-07-19
chong_zh 写道
也许open的那套测试系统对象数确实多很多呢,会不会恰好业务load有不同使得两套系统状态出现这么大的差别

 

两台测试机的业务逻辑是一致的,在同样的机器上切到oraclejdk后,内存就降了下来,这个可能性可以排除

chong_zh 2012-07-19
muzixinly 写道
chong_zh 写道
也许open的那套测试系统对象数确实多很多呢,会不会恰好业务load有不同使得两套系统状态出现这么大的差别

 

两台测试机的业务逻辑是一致的,在同样的机器上切到oraclejdk后,内存就降了下来,这个可能性可以排除

也许可以找java heap visualize工具察看一下

Global site tag (gtag.js) - Google Analytics