无限循环中抛出的java StackOverflower错误

无限循环中抛出的java StackOverflower错误,java,memory-leaks,out-of-memory,infinite-loop,stack-overflow,Java,Memory Leaks,Out Of Memory,Infinite Loop,Stack Overflow,我使用以下函数启动jsvc守护进程以接收UDP消息: @Override public void start() throws Exception { byte[] buf = new byte[1000]; DatagramPacket dgp = new DatagramPacket(buf, buf.length); DatagramSocket sk; sk = new DatagramSocket(1000); sk.setSoTimeou

我使用以下函数启动jsvc守护进程以接收UDP消息:

 @Override
public void start() throws Exception {
    byte[] buf = new byte[1000];

    DatagramPacket dgp = new DatagramPacket(buf, buf.length);
    DatagramSocket sk;

    sk = new DatagramSocket(1000);
    sk.setSoTimeout(0);

    byte[] rcvMsg = null;


    run(sk, dgp, rcvMsg);


}
超时为0时,套接字将阻塞,直到收到另一条消息。这将触发通过以下while循环的连续运行:

 MessageConstructor tmc =null;
Message message = null;

public void run(DatagramSocket sk, DatagramPacket dgp, byte[] rcvMsg){
    while(true){
        try {
            sk.receive(dgp);
        } catch (IOException e) {
            e.printStackTrace();
        }
        rcvMsg = dgp.getData();

         tmc = new MessageConstructor();
         message = tmc.constructMessageFromBinary(rcvMsg);

        tmc =null;
        message = null;
     }


}
创建的唯一新对象是下面的MessageConstructor:

在constructTagMessageFromBinary函数中,是从ByteArrayInputStream填充的消息,该ByteArrayInputStream将接收到的UDP消息转换为int

 public Message constructTagMessageFromBinary(byte[] rcvMsg) {

Message message = new Message();
ByteArrayInputStream bais = new ByteArrayInputStream(rcvMsg);
DataInput input = new DataInputStream(bais);

    try {

        int MsgType = 0;
        MsgType = input.readShort();

        message.setType(MsgType);

        return message;

    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return null;
}
最后,消息是pojo

公共类消息{

private int type;
 //getters and setters omitted
}

我已将内存泄漏缩小到以下几行:

 tmc = new MessageConstructor();
 message = tmc.constructMessageFromBinary(rcvMsg);
如果我将它们注释掉,内存将永远不会增长,并且在守护进程运行期间保持一致

在MessageConstructor类中接收以下StackOverflower错误时,我做错了什么:

Service exit with a return value of 143
java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:616)
        at org.apache.commons.daemon.support.DaemonLoader.start(DaemonLoader.java:243)
Caused by: java.lang.NullPointerException
        at MainDaemon.start(MainDaemon.java:116)
        ... 5 more
Cannot start daemon
Service exit with a return value of 5
java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:616)
        at org.apache.commons.daemon.support.DaemonLoader.start(DaemonLoader.java:243)
Caused by: java.lang.NullPointerException
        at MainDaemon.start(MainDaemon.java:117)
        ... 5 more
Cannot start daemon
Service exit with a return value of 5
Service exit with a return value of 143
Service exit with a return value of 143
Service exit with a return value of 143
Service exit with a return value of 143
Service exit with a return value of 143
Service exit with a return value of 143
Service exit with a return value of 143
Service exit with a return value of 143
java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:616)
        at org.apache.commons.daemon.support.DaemonLoader.start(DaemonLoader.java:243)
Caused by: java.lang.StackOverflowError
此代码似乎不执行任何I/O操作。
incomingBinaryMessage
不是方法调用,而是对现有
字节[]
的对象引用

循环反复运行,一次又一次地创建相同的消息


一般来说,GC应该跟上您,因为您正在丢弃每个循环中的消息和
MessageCreator
实例。但是,您没有显示的一段代码,
Message
的构造函数可能会保存对消息的引用(即,将它们添加到映射?)并防止它们被GC’ed。

我对此不是100%确定,因此我将提供不止一个建议,希望它们的组合能够解决您的问题。我也会“大声打字”,所以请原谅我,如果你是一个高级用户,其中一些是非常明显的

你有一个本质上无限的循环。此循环创建一个字节数组对象,该对象具有分配给它的数据。创建MessageCreator引用并为其分配对象。创建空消息引用,输入try块,然后为该引用指定一个对象(值)。这个赋值,或者特别是创建赋值的方法,就是问题所在,让我们来看看

createMessage方法接受一个字节数组,该数组是原始字节数组(rcvMsg)值的副本。它是自己的引用,但指向堆上的同一对象。在实际方法中,您创建了一个消息引用和对象。创建BAIS引用并指向相应的BAIS对象,该对象接受字节数组引用。这意味着BAIS对象指向原始字节数组值。然后就是DIS,它基本上是本地封装BAI的

try块创建对值0的int引用,然后立即将其重置为input.readShort()的值。这将读取原始字节数组中的值。将消息类型设置为该值,然后返回消息

退出该方法时,对您创建的消息对象的引用将被销毁。幸运的是,您可以通过return方法传递该引用。所以那个物体是安全的。不幸的是,您的输入流没有打开!我不确定jvm可能会把它放在一边,因为它仍然是开放的。如果有,更重要的信息是它仍然有一个对字节数组值的引用,从而使它们保持活动状态。下次执行循环时,它会丢弃旧的rcvMsg引用,但不会丢弃它指向的对象,因为该对象仍有引用。在每次迭代中,堆上有越来越多的字节数组,直到内存耗尽

当注释掉方法调用时,您永远无法打开(并保持打开)数据流,因此底层对象(字节数组)永远没有持久引用,因此被垃圾收集器销毁

TLDR:关闭您的流。添加
input.close()之前<代码>返回消息(可能需要更新的try/catch)


同样,我也不确定这一点,但对我扭曲的逻辑来说,这是有意义的。

问题是我在循环中打开了一个数据库连接,但没有关闭它。

看起来不错,我看到的唯一可能性真的很奇怪。。。您使用的是IPv4还是IPv6?因为IPv6允许非常大的数据报。我正在使用ipv4,所有这些数据报都很小。我有两个想法:1)您是否尝试过检查
rcvMsg
是否为空,如果为空,是否跳过两行有问题的行?2) 您是否尝试过将
tmc
message
声明放在
run()
方法中?太特殊了。这与在无限循环中创建对象时抛出堆栈溢出有关。这如何不适用于广泛的受众@user829755?incomingBinaryMessage是一个UDP数据包,看起来像:byte[]rcvMsg=datagrampacket.getData();我已经更新了消息pojo asw。它可能是一个UDP数据包,但在循环中没有修改它的内容。一旦启动循环,它就会一直运行到外部停止,一遍又一遍地重新处理同一个输入数据包。嗨,Russell,我添加了close。这并没有解决问题。再次感谢你的帮助。
    public void run() {             
        while(!stopped){

            byte[] rcvMsg = incomingBinaryMessage;

            MessageCreator tmc = new MessageCreator();
            Message message = null;
            try {
                message = tmc.createMessage(rcvMsg);
            System.out.println(message);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }