使用mvn插件执行工程单元测试OOM的解决办法
问题:同事的一个工程最近几天使用mvn test跑单元测试回归时,每天都会报“org.apache.maven.surefire.booter.SurefireExecutionException:PermGen space; nested exception is java.lang.OutOfMemoryError: PermGen space”这个错误。
拿到问题后,我第一想法就是让他去maven_home/bin目录下的mvn文件中增加MAVEN_OPTS参数来调整PermGen的大小,给了她这个设置:MAVEN_OPTS=-Xms1024m -Xmx1024m -XX:PermSize=128m-XX:MaxPermSize=128m。由于这个问题也是偶发,改了之后的两天,确实没有再重现了。但第三天,她又给了我一样的报错截图....
于是纠结了......没有思路.......
然后,无意中发现一个现象,当我执行mvn test的时候,通过ps -ef | grep java查看当前机器运行的的java进程,发现除了执行maven主程序的java进程,伴随的还有一个带了很多surefire字样的java进程,之前只见过maven有一个surefire这个名字的插件,但一点都不熟悉。这时马上有一个怀疑:单元测试类不是在maven的主进程中执行的,所以我加了MAVEN_OPTS之后执行测试时PermGen还是内存不足。于是去搜了一下,看到了这个帖子: http://www.cnblogs.com/discuss/archive/2010/10/27/1862225.html,有了结论:在执行mvn test时,maven会启动一个fork进程来运行所有的单元测试类,所以我需要设置的是这个fork进程的jvm参数。
这个参数配置也不好找,网上有一片surefire参数配置的文章,但是里面没有提到如何配置jvm启动参数,情急之下我还找了surefire人员的开发人员邮件组,用蹩脚英文写了封邮件,过了一会又回信,开心了一把,打开一看,是系统退信…..
不过最终还是让我找到了 http://maven.apache.org/plugins/maven-surefire-plugin/examples/system-properties.html这个地址,在这篇文章的最末尾,看到了<argLine>….</argLine>的配置,于是在单元测试的工程中加了插件的配置,如下所示:
这里的配置还有一个provider配置的问题,默认情况下surefire会根据工程中junit的版本来选择provider等,具体的解释可以看: http://maven.apache.org/plugins/maven-surefire-plugin/examples/junit.html。
问题解决了之后倒是冒出关于这个插件更丰富的配置的文章: http://maven.apache.org/plugins/maven-surefire-plugin/test-mojo.html,在这里甚至发现了一个forkMode的参数,原来运行mvn test也不是一定要启动另外一个fork进行的,通过forkMode可以修改这个配置,forkMode默认值是once,把forkMode参数设置成never,单元测试跑的时候就会由maven的主进程来跑了,也就是说这时候再通过MAVEN_OPTS来进行设置jvm参数也是可以行得通的了。