Strategy for debugging surefire “The forked VM terminated without saying properly goodbye. VM crash or System.exit called ?”

夙愿已清 提交于 2019-11-28 05:51:47

Steps:

(1) Run mvn with the -e and -X options to get more debug information.

(2) Look for "Error" in the output. In my case, when I ran the mvn command, part of the output included:

[ERROR] Command wascmd.exe /X /C "C:\dev\dev-tools\.....

(3) Execute the problematic command directly in the command shell.

In my case, executing

cmd.exe /X /C "C:\dev\dev-tools\....

from the command line resulted in an OutOfMemoryError.

Following Maven Surefire documentation, you can execute the forked VM in debug mode, if it always fails. You can then debug your code until it exit.

FWIW, I have experienced this error when the JVM ran out of memory during the maven build. On linux this was detected by OOM killer, which ended up generating kernel messages like Aug 28 20:53:27 ip-xxx-xxx-xxx-xxx kernel: [248686.775455] java invoked oom-killer: gfp_mask=0x201da, order=0, oom_score_adj=0.

I guess on a mac you'd just want to monitor your memory usage with ActivityMonitor.

Writing here the strategy that i used to help others who are stuck with this problem.

It is possible to leverage the SecurityManager to throw an exception when System.exit() is called. you can then examine the stack trace to see exactly who called exit(). This is especially useful if the call to exit was made from code hidden inside one of the jars you are depending on and not from your own code.

private static void forbidSystemExitCall() {
    final SecurityManager securityManager = new SecurityManager() {
        public void checkPermission( Permission permission ) {
            if( permission.getName().startsWith("exitVM") ) {
                throw new RuntimeException("Something called exit ") ;
            }
        }
    } ;
    System.setSecurityManager( securityManager ) ;
}  
Chad Van De Hey

If anyone is including a custom argLine argument, you must reconsider because it is likely the source of your issues with the memory allocation.

For Example (I used to have):

<argLine>XX:MaxPermSize=4096m ${argLine}</argLine>

Now I use hard specified values:

<argLine>-Xmx1024m -XX:MaxPermSize=256m</argLine>

For whatever reason, Applications that integrate with Surefire such as Jacoco, dont request enough memory to coexist with the testing that happens at build time.

(more information can also be found at this s.o. question (1))

(1)-maven jacoco: not generating code coverage report

What you may want to check is the argline setting for surefire or failsafe in build/pluging/plugin config in your pom. I had something improper in there that caused the forked vm to fail (Ironically, i put maven.failsafe.debug in there to help debug an earlier forking crash).

Changing the configuration of the plugin should resolve the problem:

<project>
  [...]
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>3.0.0-M1</version>
        <configuration>
          <useSystemClassLoader>false</useSystemClassLoader>
        </configuration>
      </plugin>
    </plugins>
  </build>
  [...]
</project>

As suggested in this post and in the main documentation of the plugin.

JVM options that can help:

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=c:/dumps/

Note: You can use forward slashes.
Note 2: Make sure the folder exists and that the process has write permission. On recent windows systems, C:\ is write protected.
Note 3: Make sure you have enough free space to write the dump. The Java 9 documentation mentions that the system's temp folder will be used when the disk is full.

If there is no dump file, then you JVM didn't run out of memory.

The next option is -XX:ErrorFile= which allows to the JVM to log fatal errors.

-XX:+ShowMessageBoxOnError shows an error dialog if the JVM crashes.

Note: You can change the flags of a running JVM using the jinfo command.

Pass these options to Maven Surefire via the argLine option:

<build>
    <plugins>
        <plugin>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
                <!-- -XX:HeapDumpPath=C:\ -XX:+ShowMessageBoxOnError  -->
                <argLine>@{argLine} -XX:+HeapDumpOnOutOfMemoryError -Xmx1g -XX:HeapDumpPath=H:/dumps/ -XX:ErrorFile=H:/dumps/ -XX:+ShowMessageBoxOnError</argLine>
            </configuration>
        </plugin>
    </plugins>
</build>

The strange @{argLine} at the beginning allows other plugins like Jacoco to inject their options. For this to work, you need to add an empty property:

<properties>
    <argLine></argLine> <!-- Fallback when Jacoco isn't active. -->
</properties>

You can verify that it works when the error happens: Maven will then dump the whole command line used to start the forked JVM.

I just delete all the maven repository and run maven clean install. Then the issue is gone.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!