简体   繁体   English

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

[英]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 . 我使用while(true)无限循环来允许应用程序不断“监听”通过控制台的用户输入和来自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). 无限循环显然不是实现此目的的最佳方法-毫不奇怪,仅在程序运行约一分钟后(我的计算机迷就尖叫),我得到了OutOfMemoryError: Java Heap space

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 谢谢

Try printing the value of is.readInt() . 尝试打印is.readInt()的值。 It might be possible that you are reading a garbage value and trying to allocate that much memory resulting in the OutOfMemoryError. 您可能正在读取垃圾值并试图分配那么多内存,从而导致OutOfMemoryError。 Also put the while loop in a thread and call Thread.sleep(1000) to make the checking periodic with a 1 sec interval. 另外,将while循环放入线程中,并调用Thread.sleep(1000)使检查周期为1秒。

Some of my observations : 我的一些观察:

  • Your first loop is not infinite loop. 您的第一个循环不是无限循环。
  • You might want to sleep in between reads using Thread.slpee(1000) 您可能想使用Thread.slpee(1000)在两次读取之间睡眠
  • Release byte array after you are done with it. 完成后释放字节​​数组。 bytes = null; 字节=空; // last statement in your second if check //第二个if语句中的最后一个语句

There are two problems. 有两个问题。

(1) You need to change (1)您需要更改

os.writeBytes(message);

to

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

The reason is that writeBytes discards one byte from every String . 原因是writeBytes从每个String丢弃一个字节。 From the Javadoc - 从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. 如果未引发异常,则写入的计数器将增加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 . 当然,这样做的效果是,写入的字节数实际上是调用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. (2)如果字节序列以数字字符开头,则应在调用writeInt之后写一些分隔符,例如空格。 Otherwise, the call to readInt might read the wrong number from the stream. 否则,对readInt的调用可能会从流中读取错误的数字。

Your first while loop isn't really a loop as it breaks right after assigning a value to sendsocket. 您的第一个while循环实际上不是一个循环,因为它在为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. 当您的应用程序关闭时,它将更改isRunning = false,并退出循环。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM