Recover from Out of Memory Errors in Java

In Java, as any other programming language there is a restriction of amount of memory any program can use. In languages like C the memory is limited to amount of RAM the operating system allocates to the applications or the user space. Since Java applications are technically running in the Java Virtual Machine (JVM), the applications have memory allocated by the JVM. Due to that we can start java applications with the amount of memory we need by using the –Xms and –Xmx command line parameters (Given the JVM has the memory to spare).

In Java, the memory allocation is handled by JVM. We create the objects and JVM decides where to keep those objects in heap. In languages like C we can use methods like malloc to dynamically allocate memory for objects (variables) and when we are done, the appropriate clean up methods should be called to release the memory space. There are advantages in each method, and discussing them will take another separate post.

In this post, I am going to explain how to recover from the Out of Memory errors. When a Java class faces out of memory errors, we should try to recover from those errors by reducing or blocking the service rather than crashing the application. In many cases when the application crashes due to out of memory, JVM is also impacted (which may be running other applications).

You can ask why can’t we catch the exception. First of all, catching the exception means that the error has already occurred and in complex systems letting the error happen will be costly. This method will prevent you from the error itself. When the memory is lower than the defined threshold, the code is not even executed and we are taking recovery measures to free up some memory. Also if your application is using all the memory allocated to JVM, when out of memory error occurs it will end up crashing JVM so there is no point catching the exception since your application would have been crashed.

To recover from the out of memory errors, we need to simulate the error first and then find a solution to recover. So this post consists of two major parts.

Simulate Out of Memory Error

Simulating the error is pretty simple, we will create a lot of array objects in a loop for which JVM will allocate memory spaces. Once the objects reaches a threshold, the JVM throws out of memory errors. But with the current desktops having at least 1GB of RAM (with at least 100M as the max limit to JVM) we need to create thousands of objects to simulate the error. So as I mentioned in the start of this post we will use the –Xms and –Xmx options to start the program with a maximum of 2M so that we can easily simulate the error.

Create a Java Class with the following code and start with the parameter java -Xms2m –Xmx3m

public void fillMemory() throws Exception {
    int voidSpace=20;
    for (int outerIterator=1;outerIterator<50;outerIterator++) {
        System.out.println ("Iteration " + outerIterator + " Free Mem: "
            + Runtime.getRuntime().freeMemory());
        int innerIterator=10;
        int[] memoryFillIntVar=new int[voidSpace];
        do {
            memoryFillIntVar[innerIterator]=0;
            innerIterator--;
        } while(innerIterator>0);
        voidSpace = voidSpace * 10;
    }
}

When you run this class (MemoryTest.java), you will get an output which will be similar to below.

D:\temp\>java -Xms2m -Xmx3m MemoryTest
Iteration 1 Free Mem: 1826368
Iteration 2 Free Mem: 1826368
Iteration 3 Free Mem: 1826368
Iteration 4 Free Mem: 1818352
Iteration 5 Free Mem: 1738336
Iteration 6 Free Mem: 1100952
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
        at MemoryTest.fillMemory(MemoryTest.java:22)
        at MemoryTest.main(MemoryTest.java:12)

Now we have successfully simulated the out of memory error. Let’s continue to the next part where I will show how to recover from these errors.

Recover from the error

To recover from the error 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.

So we should use setLowMemory to set a threshold and once set, whenever we call the isLowMemory it will return true/false based on the available memory. The isLowMemory will allow an low memory watermark to be valid for five seconds after it was set. This stops an incorrect limit being set for ever. This could occur if other threads were freeing memory when we called Runtime.getRuntime().freeMemory().

Now let’s rewrite our earlier MemoryTest program to use these methods to recover from the error. The modification is simple, we just need to encapsulate the object creation in a if condition which checks for the memory before creating the objects. The modified code is given below.

public class MemoryTest {
    public static void main(String[] args) throws Exception {
        MemoryTest memoryTest = new MemoryTest ();
        LowMemory lowMemory = new LowMemory();
        long[] memoryFillLongVar = new long[70000];
        lowMemory.setLowMemory();
        memoryTest.fillMemory(lowMemory);
    }
    public void fillMemory(LowMemory lowMemory) throws Exception {
        int voidSpace=20;
        for (int outerIterator=1;outerIterator<50;outerIterator++) {
            System.out.println ("Iteration " + outerIterator + " Free Mem: "
                + Runtime.getRuntime().freeMemory());
            int innerIterator=10;
            if (!lowMemory.isLowMemory()) {
                int[] memoryFillIntVar=new int[voidSpace];
                do {
                    memoryFillIntVar[innerIterator]=0;
                    innerIterator--;
                } while(innerIterator>0);
                    voidSpace = voidSpace * 10;
            } else {
                System.out.println ("Memory lower than threshold to
                    continue. Exiting the loop.");
                break;
            }
        }
    }
}

Let’s run the modified code with the same command line arguments. The output is given below. Note that the class file for LowMemory.java is present in the same directory as of MemoryTest.

D:\temp\>java -Xms2m -Xmx3m MemoryTest
Iteration 1 Free Mem: 1349576
Iteration 2 Free Mem: 1349576
Iteration 3 Free Mem: 1349576
Iteration 4 Free Mem: 1341560
Iteration 5 Free Mem: 1261544
Iteration 6 Free Mem: 461528
Memory lower than threshold to continue. Exiting the loop.

This will be very useful while writing distributed J2EE applications which involves huge databases and processing of a large amount of data within a class. This will ensure there will be no data corruption and ensure the JVM (which may host multiple applications) is able to recover from the memory errors. You can always call the GC and runFinalization once this error occurs to free some memory.

Just as an additional note, in C these kind of errors can be handled as the example code given below.

int *pointer = malloc(3 * sizeof(int));
if(pointer == NULL) {
    fprintf(stderr, "Out of memory");
    exit(1);
}

Simple Proxy Server in Java

In this post, I am going to show how a simple Proxy server can be designed in Java which will provide the core functionalities of a proxy. From Wikipedia, “a proxy server is a server (a computer system or an application program) that acts as an intermediary for requests from clients seeking resources from other servers.“The proxy server generally has some resources, or has access to some resources and when it receives request from a client, it access the appropriate resource and sends back the response.

So it serves two purposes, giving access to a resource which the client do not have access and it hides the real client who needs the resource. The second part is used for the anonymous browsing in Internet using anonymous proxy servers. Although this may not be as “anonymous” as it sounds because the proxy server which you connect to can maintain logs about the clients who are connecting to the server, and also the bigger risk being the data theft. Since the “anonymous” proxy server has access to all the request you send, there is risk of that data being exposed unless there is some kind of encryption in place between the client and the proxy server.

If you are in a network, and the machine which you are using don’t have access to Internet but another machine in the same subnet has access to Internet, then you can run this proxy application in the machine which has Internet access and in your local machine, you can configure your web browser to use the IP and Port number of the machine where the proxy is running in the LAN/Network settings. Once done, you should be able to access the Internet. This is one of the practical use for proxy servers.

The proxy server which we will be designing will be a simple HTTP proxy which gets web requests based on HTTP protocol and sends back response in the same protocol. We will start by declaring some constants.

int proxyServerPortNumber = 7879;
int webServerPortNumber = 80;
String webServerIpAddress = "192.168.1.1";
final int PROXY_SERVER_TIME_OUT = 5000;
final int SOCKET_TIME_OUT = 2000;

proxyServerPortNumber defines the port where the proxy server will be listening. You can use any port number which is not used by other process / standard port.

webServerIpAddress and webServerPortNumber defines the IP/port where the server can access the resources. Since we are designing this to access websites over http, the port is defined as 80 and the IP should be a machine which has Internet access (can be localhost too)

PROXY_SERVER_TIME_OUT and SOCKET_TIME_OUT are standard parameters defined for Server and network socket timeout. You can adjust this based on your needs.

Now we need to start the Java class to bind to the port number defined and to run in a infinite loop or as a daemon thread, so that it keeps on listening for requests. In this example, we will be using the infinite loop.

try {
    serverSocket = new ServerSocket(proxyServerPortNumber);
} catch(Exception exc) {
        System.exit(0);
}

Now the process will be listening in the port 7879 for requests from clients. Now, let’s open an infinte loop and make a connection to the resource, in our case the web server.

socketProxy = new Socket(InetAddress.getByName(webServerIpAddress),webServerPortNumber);
socketProxy.setSoTimeout(PROXY_SERVER_TIME_OUT);
socket = serverSocket.accept();
socket.setSoTimeout(SOCKET_TIME_OUT);
inputStream = socket.getInputStream();

The request from the client will be received by Input Stream, so once we are connected, we will be sending this Input Stream which is nothing but a normal HTTP REQ object to the server which has the resource or as in our case the machine connected to Internet. The server will respond with the response which will be a HTTP RES over the Java Output Stream. We will be forwarding this output stream to the client which will be rendered in the application which the client requested in. That is if the request was sent through command line, the entire HTML will be printed, if its a browser the page will be rendered.

try {
    while( (intCounter = in.read()) != -1) {
        if(intCounter == -1) break;
        if(!bREQ)
            bREQ = true;
        pOutputStream.write(intCounter);
        if(byteCheckFl > 0) {
            break;
        }
        if(intCounter == 13 && intPrevCounter == 10)
            byteCheckFl++;
        intPrevCounter = intCounter;
    }
} catch(Exception e) {
    if(!bREQ) {
        continue;
    }
}

pOutputStream.flush();
pIutputStream = socketProxy.getInputStream();
outputStream = socket.getOutputStream();
try {
    while( (intCounter = pIutputStream.read()) != -1) {
        outputStream.write(intCounter);
    }
} catch(Exception e) {
}
outputStream.flush();

Make sure to close all the opened sockets and connections once the response is sent. Since this whole code is running in an infinite loop, the server will keep on waiting for the requests and sending the responses back. This is a crude implementation of the concept and there is room for a lot more improvements (like supporting SSL), but this should serve as a foundation to make the proxy a robust one.

We can easily make this Java class as a Win32 service, so that it will always run in background and starts along with the OS. That will need some work with JNI. I will explain that in a later post.