无限循环导致OutOfMemoryError:Java堆空间

时间:2013-11-21 21:24:30

标签: java

我正在写一个聊天应用程序。我使用while(true)无限循环来允许应用程序通过控制台和来自Socket的输入不断地“监听”用户输入。无限循环显然不是实现这一目标的最佳方式 - 毫不奇怪,在程序运行仅约一分钟后(我的计算机粉丝尖叫),我得到OutOfMemoryError: Java Heap space

我的问题是:如果不是通过一个无限循环,我怎样才能不断修改我的程序(或至少以小间隔修改,比如每秒一次)检查输入源,响应,然后再回到检查? / p>

代码(带有一些注释)如下:

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"));
            }
        }
    }
}

由于

4 个答案:

答案 0 :(得分:1)

尝试打印is.readInt()的值。您可能正在读取垃圾值并尝试分配导致OutOfMemoryError的大量内存。 同时将while循环放在一个线程中并调用Thread.sleep(1000)以1秒为间隔进行定期检查。

答案 1 :(得分:1)

我的一些观察结果:

  • 你的第一个循环不是无限循环。
  • 你可能想要在阅读之间睡觉 Thread.slpee(1000)
  • 完成后释放字节​​数组。 bytes = null; //如果检查你的第二个陈述

答案 2 :(得分:1)

有两个问题。

(1)您需要更改

os.writeBytes(message);

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

原因是writeBytes丢弃了每个String的一个字节。来自Javadoc -

  

将字符串作为序列写入基础输出流   字节。字符串中的每个字符按顺序写出   丢弃其高八位。如果没有抛出异常,则为计数器   写入增加s的长度。

这当然的结果是你写的字节数实际上是你调用writeInt时指定的字节数的一半。

(2)如果字节序列以数字字符开头,则应在调用writeInt后编写某种分隔符,如空格。否则,对readInt的调用可能会从流中读取错误的数字。

答案 3 :(得分:0)

你的第一个while循环实际上并不是一个循环,因为它在将一个值分配给sentocket之后就会中断。

也许你的应用程序有一个标志,如

bool isRunning=true;

你可以做到,

while(isRunning) 

当你的申请被关闭时,它会改变isRunning = false,&踢出循环。