6

I am experiencing what I consider a strange behaviour for a Java application. I am using Spring Boot 1.4.1 to develop a REST Service. Due to a bug in my code, an invocation to the service results in an OutOfMemoryError.

Surprisingly, the service responds to the request that generates the error with the following message:

{
  "timestamp": 1487862480405,
  "status": 500,
  "error": "Internal Server Error",
  "exception": "java.lang.OutOfMemoryError",
  "message": "No message available",
  "path": "/entity/exportCsv"
}

So far so good. What is more surprisingly is that the REST service does not shutdown after experiencing the Error. Someone said that after an Error the best thing to do is to properly log it and shutdown everything. The presence of an error should mean that the system is in an unrecoverable state.

Why does Spring MVC adopt such a strange policy in case of Error? Is it possible to force the exit from the application (the REST service) after an Error happened?

If you want to reproduce the above use case, just use the following code.

@RestController
@RequestMapping("/entity")
class Controller {
    @RequestMapping(value = "/exportCsv", method = RequestMethod.GET)
    ResponseEntity exportCsv() {
        if (true)
            throw new OutOfMemoryError();
        return null;
    }
}

Thanks to all.

EDIT: if you do think that catching an Error is a normal way to develop Java applications, please, try to have a look to these references:

Community
  • 1
  • 1
riccardo.cardin
  • 7,971
  • 5
  • 57
  • 106
  • I'm not sure what exactly you want to know. You seem to imply that Spring should shut down anything. – a better oliver Feb 24 '17 at 09:02
  • @zeroflagL I am asking if it is possible to force exit of the REST service in case of an `OutOfMemoryError`. Related to this, I am asking if someone knows why Spring implements the above policy. Thanks. – riccardo.cardin Feb 24 '17 at 09:05

3 Answers3

5

When running your application, you can specify the behavior of your application when an error like this happens with the following arguments:

  • -XX:+HeapDumpOnOutOfMemoryError : this will create a dump which can be analysed afterwards. The dump will be located at the location given at -XX:HeapDumpPath=some_path.
  • -XX:OnOutOfMemoryError=path_to_some_script.sh : this will run a script (it must be runnable by the same user which runs the application) when the application returns an error as an OutOfMemory
  • -XX:OnError=path_to_some_script.sh : same as before, but for more generic exceptions.

Reference: http://www.oracle.com/technetwork/java/javase/clopts-139448.html

Sergio Lema
  • 1,491
  • 1
  • 14
  • 25
  • Sorry, in which way this answer to my question? – riccardo.cardin Feb 23 '17 at 16:54
  • _Why does Spring MVC adopt such a strange policy in case of Error?_ Spring has a default behavior which can't do more when a JVM error happens; _Is it possible to force the exit from the application (the REST service) after an Error happened?_ Yes, see my answer above. – Sergio Lema Feb 23 '17 at 16:59
  • Spring works as any standard JVM application. That is an answer to your question. – Michał Mielec Feb 23 '17 at 17:02
  • So, your solution is to point to a script that will try to kill the Spring applcation in case of `OutOfMemotyError`? – riccardo.cardin Feb 23 '17 at 17:02
  • The end of this script should be something like _kill_ or _restart_. But you can perform whatever analyse/dump tasks before which can be useful to investigate the reasons of the error. – Sergio Lema Feb 23 '17 at 17:04
  • @MichałMielec in this case Spring *is not* working as any other JVM application. In case of an `Error` a standard JVM application will stop. – riccardo.cardin Feb 23 '17 at 17:04
  • You can catch any `Error` in a JVM application. Spring must do it and return a default message when the service is in a degraded mode. – Sergio Lema Feb 23 '17 at 17:07
  • What you can do is not equals to what you should do. Many articles state that `Error`s must not be catch, because you have no guarantees that you will be able to recover the system from them. Look at this SO question for example [When to catch java.lang.Error?](http://stackoverflow.com/questions/352780/when-to-catch-java-lang-error) – riccardo.cardin Feb 23 '17 at 21:29
  • @SergioLema your solutions cannot work because Spring is intercepting the thrown `OutOfMemoryError`. So the error will never reach the JVM. Please, update your answer or delete it. – riccardo.cardin Feb 24 '17 at 09:37
  • Spring Boot catch the `OutOfMemoryError` and let you know about it, but it also informs the JVM about it, so the JVM arguments I described in my comment are taken into account (I'm currently using them in a production application with Spring Boot and it works fine). – Sergio Lema Feb 24 '17 at 10:00
1

I would say that in the world of web apps this is not suprising at all.

Imagine a RestController as a web page. If it contains an error, the web server nor the application that generates the page is expected to stop working. This error is usually a local or temporary problem related to your request. In these situations the web server should instead respond with HTTP status 500.

Spring even has an built-in error handling feature that lets you to handle each specific error differently. See this article by Paul Chapman for more info.

UPDATE: Regarding your inquiry about the OOM error handling: I think you missed how memory management and object allocation in JVM works. See Understand the OutOfMemoryError Exception.

stuchl4n3k
  • 588
  • 5
  • 14
  • I don't agree. The behaviour you described is true for `Exception`s. However, an `OutOfMemoryError` is not a "temporary problem. How the system will respond 500 to the request if there is no memory available at all? – riccardo.cardin Feb 23 '17 at 16:56
  • Of course it can be temporary - imagine e.g. processing a huge input. There usually is memory available to handle the exception (the GC is still there). – stuchl4n3k Feb 28 '17 at 10:32
0

java.lang.OutOfMemoryError won't stop the Spring Application. If you are running your application in a container then health-check hook would let container manager know that your application is not in right condition so it would automatically dispose the current pod and would create fresh one.

You should always give JAVA_TOOL_OPTIONS as environment variable to use the POD memory effectively. By default your Java Springboot app will use just 25% of maximum memory.

e.g. If you allocate 4 GB memory to your POD then your Java Springboot application will use max 1 GB of RAM and in turn you will not use the allocated resources properly. Always set JAVA_TOOL_OPTIONS environment variable for memory allocations.