Like any other programming language, Java puts a restriction on amount of memory you can use for the execution of programs. The difference being – Most other languages like C++, PHP, user has the power and the pain of allocating and handling the memory operation.
Since Java uses JVM, the developer’s pain of thinking about memory allocation is gone but sudden deaths like OutOfMemoryException become inevitable for Memory intensive programming. This is exactly what we are going to discuss here – How to prevent it and recover from it.
Need of Recovery
The advantage can be seen almost everywhere. Let’s take example for distributed J2EE applications, which involves huge databases and processing of a large amount of data within a class, sudden death of Java execution threads can cause trouble by creating stale transactions, database connections and what not. If we can, somehow, prevent this situation, it will ensure there will be no data corruption and the JVM, which may host multiple applications or atleast multiple threads, is able to recover from the memory errors. You can always call the GC & runFinalization once this error occurs to free some memory.
Methodology
The easiest prevention, as you already know is to increasing the JVM arguments to increase maximum memory. But it’s not what we intend to discuss, rather a better approach.
Runtime.getRuntime().freeMemory()
freeMemory() gives the amount of free memory at runtime. This gives you free memory at any instant, but it changes as the memory requirements change for the program when JVM actively allocates more space for execution till the upperlimit -Xmx is reached.
We need an effective way to tackle this. We will be using one of the utility classes from Apache Derby V10.6 Internals called LowMemory. The class has the below 2 methods drawing our intrest.
void setLowMemory() – Sets a low memory watermark where the owner of this object just hit an OutOfMemoryError.
boolean isLowMemory() – Returns true if a low memory water mark has been set and the current free memory is lower than it.
public class MemoryTest { public static void main(String[] args) throws Exception { MemoryTest memoryTest = new MemoryTest(); LowMemory lowMem = new LowMemory(); long[] memLongVar = new long[80000]; lowMem.setLowMemory(); memoryTest.fillMemory(lowMem); } public void fillMemory(LowMemory lowMem) throws Exception { int voidSpace = 20; for (int outIterator=1;outIterator<1024;outIterator++) { System.out.println ("Iteration " + outIterator + "Free: " + Runtime.getRuntime().freeMemory()); int inIterator=10; if (!lowMemory.isLowMemory()) { int[] memIntVar = new int[voidSpace]; do { memIntVar[inIterator]=0; inIterator--; } while(inIterator>0); voidSpace = voidSpace * 10; } else { System.out.println ("Memory lower than threshold, will exit."); doSomeRecoveryMechanism(); // Quit with Notification,prevent other Threads from dyingbreak;
} } } }
Updated: By following an application dependent logic to gracefully exit, now your other enterprise applications will not all die in one fusion reaction, and we can prevent the single point of failure from occuring to a great extent. Chance are there that other threads finish the execution ion next couple of seconds and it frees-up some memory for your applications.
If other application continue to eat more memory, there is no way you can recover from this.
I’m open to your comments, do let me know what you think.
loading...
loading...
This probably won't work in a production environment. Many production environments (including the one I work on) explicitly disable System.gc(). In fact, many vendors recommend this (you can really mess up the GC / JVM memory strategy by doing explicit calls to System.gc. Besides, if you have a real memory “leak” (holding on to refs no longer needed, etc.) this won't help – the GC will never free them.
You're better off analyzing your memory profile with VisualGC or some other tool and a adjusting your JVM memory settings appropriately.
loading...
loading...
Do not try to recover from an OutOfMemory, this is a really bad idea.
I will cite the excellent tips provided in the book “The Pragmatic Programmer” :
> Crash Early
> A dead program normally does a lot less damage than a crippled one.
Let the system crash and as jgulla said, profile your application and adjust your JVM memory system correctly. This will be a lot better than trying to stay alive in a really bad state where everything can happen and bring your system to its knees.
loading...
loading...
I agree with jgulla. I don't think this will buy you much. Especially if you have a leak. But also because gc() merely suggests a GC to run. Even if your production environment allows the gc() method to run, if you are in a situation where you NEED to do this programmtically, it is probably already to late and your collector is already thrashing because it can't recover enough memory to get below the threshold.
loading...
loading...
The definition of an OutOfMemoryError is greater than 98% of the time spent in GC with less than 2% freed memory. I don't see how calling System.gc() is going to help you in this instance as the system is already spinning it's wheels trying to free up memory.
loading...
loading...
Never handle OutOfMemoryException with your hand as JVM already does this for you. And if one application has an OutOfMemoryException, this will be resulted from even a bad programming or a bad design.
loading...
loading...
Modified to make more sense. No GCs called, but current thread shutdowns gracefully, possibly other apps/threads can survive bit longer if one of them finishes or reduces the memory mark.
loading...
loading...