5

So today while learning Java, I finally encountered this particular error. It seems that this error is pretty prevalent and trying to recover from it has garnered mixed reactions. Some think it is useful in certain scenarios so its a good 'good to know', some have used it in their projects, while others vehemently oppose the idea of catching this error and then a lot of others are just as confused as me.

Edit: Oh btw, this is the error that I have encountered. I wish to catch these errors and decrease the value of incrementor by 1/10th next time until another error is found
(and so on... until I find the upper bound) This is the error I've encountered

Since I'm taking my baby steps in Java and cannot find anything much specific on this topic, I'd like to ask your help on this particular example:

public class SpeedDemoClass {
        static int iterations=0;
        static int incrementor=10000000;
    public static void main(String[] args) {
        while(incrementor>1){
            try{
              iterations=iterations+incrementor;
              iterator(iterations);
            }
            catch(Exception e){
                System.out.println("So this is the limiting error: "+e);
                iterations=iterations-incrementor;
                incrementor=incrementor/10;
                iterations=iterations+incrementor;
            }
        }
        System.out.println("The upper limit of iterations is: "+iterations);
    }

    public static void iterator(int a){
            long start_time= System.currentTimeMillis();
            StringBuilder sbuild= new StringBuilder("JAVA");
            for(int i=0;i<a;i++){
                sbuild.append("JAVA");
            }
            System.out.println("Performing "+a+" append operations;"
                    +"process completed in :"
                    +(System.currentTimeMillis()-start_time)+"ms");
    }
}

Did you try compiling it?

Ofcourse, it does not work

Here's a short description on what I'm trying to do!

I am trying to do the following:

  1. Initialize incrementor=10000000 and iterations=0 and pass the result of incrementor=incrementor+iterations to iterator().
  2. If there is an Error, the program should catch it and then decrease iterations* by **incrementor, then divide incrementor by 10, then try this again
  3. Repeat steps 1 to 2 until, it starts working.
  4. Goal is to find values of iterations where it produces error and stay below that level after each iteration until the upper limit of the value of iterations is found
    (i.e. when incrementor becomes 0)

With my own manual tests, I have found out the value of this to be 92,274,686. That's the magic number. I don't know why it is so, and whether or not it is that value for my own computer only. It would be awesome if someone could post a modified code that could spit out this result.

Community
  • 1
  • 1
Siddhant Rimal
  • 975
  • 2
  • 11
  • 32
  • 5
    What is your question? – talex Aug 29 '16 at 14:08
  • 2
    Thank you for posting such a well-structured question. – byxor Aug 29 '16 at 14:09
  • 1
    Well-structured yes, but ultimately unclear what the actual question is. – Oliver Charlesworth Aug 29 '16 at 14:10
  • I wish to increment the value of possible iterations(I) by incrementor(X) until I get an error. Then when I catch the error, I'll change the value of X into 1/10th its value and repeat the process until I get an error again, catch it and do the same again. This repeats until I've 1/10th X enough times to reach 1 and then on the next error, I reach X=0; which indicates the end of iteration. I believe, I'll be able to find 92,274,686 if I do just that. I don't know my way around Java yet. I was hoping for help :) – Siddhant Rimal Aug 29 '16 at 14:15
  • You may find useful info in this related question: http://stackoverflow.com/questions/37335/how-to-deal-with-java-lang-outofmemoryerror-java-heap-space-error-64mb-heap – Ravindra babu Aug 30 '16 at 04:32

5 Answers5

3

You catch Exception, but OutOfMemoryError is an Error. Note that Error and Exception are two different classes in Java! Both implement Throwable, though.

The catch clause restricts the type of Throwable classes to be caught. As Error is not an Exception, your code won't catch OutOfMemoryError.

Martin Nyolt
  • 4,463
  • 3
  • 28
  • 36
3

That "magic number" will change if you allocate some extra objects that use up memory, use a PC with less memory etc. or allocate memory smart. Trying to estimate memory consumption brute-force is a bad idea!

Instead, understand how Java memory allocations work, how the memory layout of a string builder is, and how to control this. Here, you should study the method ensureCapacityInternal.

Look at the error you get - in particular the classes and line numbers.

I bet that if you replace this line:

StringBuilder sbuild= new StringBuilder("JAVA");

by

StringBuilder sbuild= new StringBuilder(500000000);

Then you get much further before seeing an OOM error. Catching this error is not a very clever way. There are some nice variants to observe memory consumption; but you really should use them only once you have understood memory organization of Java, so you don't draw wrong conclusions.

Your PC probably has 8 GB of RAM? Try using java -Xmx7500m. You may be able to go 3x as far. Because by default, Java only uses 25% of your memory simply to allow other processes to use some memory, too. If you want Java to use all your memory, you have to tell it that this is desired.

Has QUIT--Anony-Mousse
  • 76,138
  • 12
  • 138
  • 194
2

bro to catch the outofmemoryerror just replace Exception in catch with OutOfMemoryError

catch(OutOfMemoryError e)

Yub Basnet
  • 36
  • 3
  • I was about to post this answer. I stumbled upon this myself a few minutes ago in an [SO Question](http://stackoverflow.com/a/2679617/5040900) I looked at earlier this day. _I don't know why I missed it haha_ – Siddhant Rimal Aug 30 '16 at 16:31
1

Out of Memory generally means you can't do much else, the VM is already crashing. While it might seem you can doe something, like deallocate memory, Java does all memory management for you. You can't deallocate anything, you can dereference objects and then trigger garbage collection, but at the moment the exception occurs it's too late. Almost anything you could do, requires memory allocation, and you have none.

In general all errors that are thrown by the VM cannot be recovered from. Usually because the VM itself is unstable, and you don't have access to the internals of the VM to fix it. Not only that, but it would be the rare case that your software could fix it.

Jim Barrows
  • 3,634
  • 1
  • 25
  • 36
  • 1
    The JVM throwing `OutOfMemoryError` does not make it unstable. It just signals - as any other exception - that the code within the `try` block failed to execute. Also, this does not mean that the VM has crashed. Only *the application* crashes if it does not (or cannot) handle the error. In this question, recovering from the error is easy, as the memory will be freed as soon as the `iterator` method returns (normal or abnormal). – Martin Nyolt Aug 29 '16 at 14:52
1

I was going to post this solution but somebody beat me to it. Earlier this day, I seemed to have overlooked a solution presented in one of the alternative questions of this sort that I've mentioned in the beginning of this question.

Well, just for general courtesy, so that people in the future do not overlook a right-at-your-face solution like I have, I'm posting an answer as easy as they come*. Here are the little modifications I've made that made it happen. It seems, it is possible to catch java.lang.OutOfMemoryError although I do not yet know the implications of what I have really done.

* Please feel free to correct me and read the end of this answer :)

I'll update this answer in the future reflecting on things that I might discover later(like discrepancies and such)

So without further ado, here's the code in its raw glory:

public class SpeedDemoClass {
    static int iterations=0;
    static int incrementor=10000000;
    public static void main(String[] args) {
        while(incrementor>0){
            try{
                iterations=iterations+incrementor;
                int a = iterations;
                long start_time= System.currentTimeMillis();
                StringBuilder sbuild= new StringBuilder("JAVA");
                for(int i=0;i<a;i++){
                    sbuild.append("JAVA");
                }
                System.out.println("Performing "+a+" append operations;"
                    +"process completed in :"
                    +(System.currentTimeMillis()-start_time)+"ms");
            }
            catch(OutOfMemoryError e){
                System.out.println("OutOfMemory bound reached beyond this point with error: "+e
                +"\nReverting back, and Changing the value of incrementor by 1/10th...");
                iterations=iterations-incrementor;
                incrementor=incrementor/10;
                iterations=iterations+incrementor;
            }
        }
        System.out.println("The upper limit of iterations is: "+iterations);
    }
}

Changelog:
If it is not yet apparent, I have made some tiny changes to the original code.
(1) I ditched the method iterator() because I realize now that it made it harder for people to realize the intent of the question.
(2) I changed catch(Exception e) to catch(OutOfMemoryError e) . Turns out there is a native solution available, and I had overlooked it earlier.

OUTPUT:

Output-Part-1 Output-Part-2

It seems to work perfectly for me and now I have found the magic number. I welcome all comments that can indicate this answer is wrong and why? :)

Community
  • 1
  • 1
Siddhant Rimal
  • 975
  • 2
  • 11
  • 32