asaini007
asaini007

Reputation: 836

Infinite loop causes OutOfMemoryError: Java heap space

I'm writing a chat application. I use a while(true) infinite loop to allow the application to constantly "listen" to both user input through the console and input from a Socket. The infinite loop clearly isn't the optimal way to accomplish this - not surprisingly, I get an OutOfMemoryError: Java Heap space after only about a minute of the program running (and my computer's fans screaming).

My question is: if not through an infinite loop, how can I modify my program to constantly (or at least at small intervals, like once every second) check the input sources, respond, and then go back to checking?

The code (with some notes) is below:

import java.io.*;
import java.net.*;

public class Main {
    public static void main(String[] args) throws IOException, ConnectException {
        ServerSocket receiveServerSocket = new ServerSocket(Integer.parseInt(args[0])); // args contains two port numbers
        Socket sendSocket;
        while(true) { // note - I use the exact same infinite loop strategy here, except in this case an OutOfMemoryError is not thrown
            try {
                sendSocket = new Socket(InetAddress.getLocalHost(), Integer.parseInt(args[1]));
                break;
            } catch (ConnectException e) {}
        }
        DataOutputStream os = new DataOutputStream(sendSocket.getOutputStream());
        Socket receiveSocket = receiveServerSocket.accept();
        DataInputStream is = new DataInputStream(receiveSocket.getInputStream());
        BufferedReader input = new BufferedReader (new InputStreamReader(System.in));
        String message;
        while(true) { // Here's the infinite loop in question
            if(input.ready()) { // "checks" to see if the user has entered text
                message = input.readLine(); // responds
                os.writeInt(message.getBytes().length);     
                os.writeBytes(message);
            }
            if(is.available() > 0) { // checks to see if Socket has received text
                byte[] bytes = new byte[is.readInt()]; // responds (Incidentally, this is the specific line where the OutOfMemoryError occurs)
                is.read(bytes,0,bytes.length);
                System.out.println(new String(bytes,0,bytes.length,"UTF-8"));
            }
        }
    }
}

Thanks

Upvotes: 0

Views: 1948

Answers (4)

Dawood ibn Kareem
Dawood ibn Kareem

Reputation: 79847

There are two problems.

(1) You need to change

os.writeBytes(message);

to

os.write(message.getBytes(), 0, message.getBytes().length);

The reason is that writeBytes discards one byte from every String. From the Javadoc -

Writes out the string to the underlying output stream as a sequence of bytes. Each character in the string is written out, in sequence, by discarding its high eight bits. If no exception is thrown, the counter written is incremented by the length of s.

The effect of this of course is that the number of bytes you've written is actually half of the number of bytes you specified when you called writeInt.

(2) You should write some kind of separator character such as a space after the call to writeInt, in case the byte sequence begins with numeric characters. Otherwise, the call to readInt might read the wrong number from the stream.

Upvotes: 1

Aakash
Aakash

Reputation: 1900

Try printing the value of is.readInt(). It might be possible that you are reading a garbage value and trying to allocate that much memory resulting in the OutOfMemoryError. Also put the while loop in a thread and call Thread.sleep(1000) to make the checking periodic with a 1 sec interval.

Upvotes: 1

neo
neo

Reputation: 1074

Some of my observations :

  • Your first loop is not infinite loop.
  • You might want to sleep in between reads using Thread.slpee(1000)
  • Release byte array after you are done with it. bytes = null; // last statement in your second if check

Upvotes: 1

yonitdm
yonitdm

Reputation: 441

Your first while loop isn't really a loop as it breaks right after assigning a value to sendsocket.

Maybe have a flag for your application like

bool isRunning=true;

and you can do,

while(isRunning) 

and when your application is closed it'll change isRunning=false, & kick out of the loop.

Upvotes: 0

Related Questions