Asked  7 Months ago    Answers:  5   Viewed   58 times

Documentation for java.lang.Error says:

An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch

But as java.lang.Error is a subclass of java.lang.Throwable, I can catch this type of Throwable.

I understand why it's not a good idea to catch this sort of exception. As far as I understand, if we decide to catch it, the catch handler should not allocate any memory by itself. Otherwise OutOfMemoryError will be thrown again.

So, my question is:

  1. Are there any real world scenarios when catching java.lang.OutOfMemoryError might be a good idea?
  2. If we decide to catch java.lang.OutOfMemoryError, how can we make sure the catch handler doesn't allocate any memory by itself (any tools or best practices)?

 Answers

78

There are a number of scenarios where you may wish to catch an OutOfMemoryError and in my experience (on Windows and Solaris JVMs), only very infrequently is OutOfMemoryError the death-knell to a JVM.

There is only one good reason to catch an OutOfMemoryError and that is to close down gracefully, cleanly releasing resources and logging the reason for the failure best you can (if it is still possible to do so).

In general, the OutOfMemoryError occurs due to a block memory allocation that cannot be satisfied with the remaining resources of the heap.

When the Error is thrown the heap contains the same amount of allocated objects as before the unsuccessful allocation and now is the time to drop references to run-time objects to free even more memory that may be required for cleanup. In these cases, it may even be possible to continue but that would definitely be a bad idea as you can never be 100% certain that the JVM is in a reparable state.

Demonstration that OutOfMemoryError does not mean that the JVM is out of memory in the catch block:

private static final int MEGABYTE = (1024*1024);
public static void runOutOfMemory() {
    MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
    for (int i=1; i <= 100; i++) {
        try {
            byte[] bytes = new byte[MEGABYTE*500];
        } catch (Exception e) {
            e.printStackTrace();
        } catch (OutOfMemoryError e) {
            MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage();
            long maxMemory = heapUsage.getMax() / MEGABYTE;
            long usedMemory = heapUsage.getUsed() / MEGABYTE;
            System.out.println(i+ " : Memory Use :" + usedMemory + "M/" +maxMemory+"M");
        }
    }
}

Output of this code:

1 : Memory Use :0M/247M
..
..
..
98 : Memory Use :0M/247M
99 : Memory Use :0M/247M
100 : Memory Use :0M/247M

If running something critical, I usually catch the Error, log it to syserr, then log it using my logging framework of choice, then proceed to release resources and close down in a clean fashion. What's the worst that can happen? The JVM is dying (or already dead) anyway and by catching the Error there is at least a chance of cleanup.

The caveat is that you have to target the catching of these types of errors only in places where cleanup is possible. Don't blanket catch(Throwable t) {} everywhere or nonsense like that.

Tuesday, June 1, 2021
 
Rocket
answered 7 Months ago
80

Update:

As of PHP 7.1, this is available.

The syntax is:

try
{
    // Some code...
}
catch(AError | BError $e)
{
    // Handle exceptions
}
catch(Exception $e)
{
    // Handle the general case
}

Docs: https://www.php.net/manual/en/language.exceptions.php#example-294

RFC: https://wiki.php.net/rfc/multiple-catch

Commit: https://github.com/php/php-src/commit/0aed2cc2a440e7be17552cc669d71fdd24d1204a


For PHP before 7.1:

Despite what these other answers say, you can catch AError and BError in the same block (it is somewhat easier if you are the one defining the exceptions). Even given that there are exceptions you want to "fall through", you should still be able to define a hierarchy to match your needs.

abstract class MyExceptions extends Exception {}

abstract class LetterError extends MyExceptions {}

class AError extends LetterError {}

class BError extends LetterError {}

Then:

catch(LetterError $e){
    //voodoo
}

As you can see here and here, even the SPL default exceptions have a hierarchy you can leverage. Additionally, as stated in the PHP Manual:

When an exception is thrown, code following the statement will not be executed, and PHP will attempt to find the first matching catch block.

This means you could also have

class CError extends LetterError {}

which you need to handle differently than AError or BError, so your catch statement would look like this:

catch(CError $e){
    //voodoo
}
catch(LetterError $e){
    //voodoo
}

If you had the case where there were twenty or more exceptions that legitimately belonged under the same superclass, and you needed to handle five (or whatever large-ish group) of them one way and the rest the other, you can STILL do this.

interface Group1 {}

class AError extends LetterError implements Group1 {}

class BError extends LetterError implements Group1 {}

And then:

catch (Group1 $e) {}

Using OOP when it comes to exceptions is very powerful. Using things like get_class or instanceof are hacks, and should be avoided if possible.

Another solution I would like to add is putting the exception handling functionality in its own method.

You could have

function handleExceptionMethod1(Exception $e)
{
    //voodoo
}

function handleExceptionMethod2(Exception $e)
{
    //voodoo
}

Assuming there is absolutely no way you can control exception class hierarchies or interfaces (and there almost always will be a way), you can do the following:

try
{
    stuff()
}
catch(ExceptionA $e)
{
    $this->handleExceptionMethod1($e);
}
catch(ExceptionB $e)
{
    $this->handleExceptionMethod1($e);
}
catch(ExceptionC $e)
{
    $this->handleExceptionMethod1($e);
}
catch(Exception $e)
{
    $this->handleExceptionMethod2($e);
}

In this way, you are still have a only single code location you have to modify if your exception handling mechanism needs to change, and you are working within the general constructs of OOP.

Wednesday, March 31, 2021
 
yosemite
answered 9 Months ago
27

Because OutOfMemoryError is an Error, not an Exception. Since OutOfMemoryError isn't a subclass of Exception, the catch (Exception e) doesn't apply.

OutOfMemoryError does extend Throwable, however, so you should be able to catch it. Here's a SO discussion on when (if ever) you should catch Errors. Generally, since you can't do anything about it, the recommendation is to not bother catching Errors in production code. But given a special case where you're trying to debug what's going on, it might be helpful.

Friday, July 30, 2021
 
ryuikuya
answered 4 Months ago
50

From https://en.wikipedia.org/wiki/Unix_signal:

SIGINT is generated by the user pressing Ctrl+C and is an interrupt

SIGTERM is a signal that is sent to request the process terminates. The kill command sends a SIGTERM and it's a terminate

You can catch both SIGTERM and SIGINT and you will always be able to close the process with a SIGKILL or kill -9 [pid].

Saturday, September 25, 2021
 
George Armhold
answered 2 Months ago
57

at first glance there's nothing wrong with your code but you're using every possible type of method that is known for being a memory waster and now that you're trying large operations you running out of memory, that was guaranteed to happen.

tips:

  • do not contatenate strings with str1 += str2 + "other val" you just created 3 new strings in memory. Use a StringBuilder instead.
  • Calling System.gc() (as some will suggest you) will not help you, because you're in a Loop doing this operation and that method only hints the system that it might be a good time to GC, but until the system actually get around to do it, you'll have crashed already.
  • If each JSON string is around 1mb and you're passing 20 of them, you're already crashing with out of memory on older devices right there with those 20mb. You'll have to re-design quite a few stuff, but my suggestion is to just remove the Map, completely remove it.

Instead you should (on the method that is creating that map) to use some type of OutputStreamto write all that data, already formatted in a temporary file. Then, to upload you'll use some type of InputStream to read from this file and write to your DataOutputStream

Alternative to the Streams is to use some other classes that bases on the same methodology as streams, they are: JsonWriter/JsonReader, but then you also have FileWriter/FileReader if it's not specific Json what you're passing, and don't forget to always wrap those with BufferedReader and BufferedWriter.

Sunday, November 28, 2021
 
Chris Herrera
answered 2 Days ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share