2012-08-10 72 views
0

我有一個簡單的應用程序來偵聽UDP消息。該應用需要無限期運行。它實例通過實例,我創建它看起來像這樣的MySQLConnect對象的單個JDBC數據庫連接:在java應用程序中出現內存不足和堆棧溢出異常,無限循環

public MySQLConnect() { 
    this.instantiateConnection(); 
} 

//Open the database connection. Done iniitally in 
//the main class and only called again if the connection 
//is closed due to an error in processing a message 
public Connection instantiateConnection() { 

    try { 

     Class.forName("com.mysql.jdbc.Driver"); 

     connection = DriverManager 
       .getConnection("jdbc:mysql://localhost:3306/mydb?" 
         + "user=user&password=pwd"); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 

    return connection; 
} 

的MySQLConnect類的構造函數是從一次一個應用程序被啓動的UDPReceiver類調用。如果出現錯誤處理並且數據庫連接已關閉,則只會再次調用它。這個類看起來像:

public class UDPReceiver { 

private static int port = 2140; 
private static int byteSize = 1024; 
private static int timeOut = 5000; 
@SuppressWarnings("unused") 
private static int count; 
static MySQLConnect dbConnect; 


    public static void main(String[] args) { 

    recvUDPMessage(); 
} 

public static String recvUDPMessage() { 
    DataTransferService dts = new DataTransferServiceImp(); 
    dbConnect = new MySQLConnect(); 

    try { 

     DatagramSocket dsocket = null; 
     if (dsocket == null) { 
      dsocket = new DatagramSocket(port); 
      dsocket.setBroadcast(true); 
      dsocket.setReuseAddress(false); 
     } 
     byte[] inbuf = new byte[byteSize]; 
     byte[] rcvMsg; 
     InetAddress fromIP; 

     DatagramPacket receivepacket = new DatagramPacket(inbuf, 
       inbuf.length); 
     dsocket.setSoTimeout(timeOut); 

     //Infinitely loop and listen for UDP messages 

     count = 0; 
     boolean loopRecv = true; 
     while (loopRecv) { 
      try { 
       count++; 
       dsocket.receive(receivepacket); 
       // temp = receivepacket.getAddress().toString(); 
       fromIP = receivepacket.getAddress(); 
       String fromIPString = fromIP.toString(); 
       rcvMsg = receivepacket.getData(); 
       String rcvString = new String(rcvMsg, 0, rcvMsg.length); 
       String rcvMessage = "Message Received from: " 
         + fromIPString + " Message: " + rcvString + "\n"; 
       System.out.println(rcvMessage); 



       ArrayList<String> al = getMessageElements(rcvString); 



       //Send array of message elements to service layer 
       dts.saveUDPMessage(dbConnect, al, Utils.getTimeStamp()); 

       loopRecv = true; 
      } catch (IOException e) { 
       System.out.println("Listening . . ."); 



       loopRecv = true; 
      } 
     } 
    } catch (SocketException e) { 
     System.err.println("Sockets Exception: " + e.getMessage()); 
    } catch (Exception e) { 
     System.err.println(" Exception: " + e.getMessage()); 

    } finally { 
     System.out.println(". . . Close DB"); 
     dts.closeDBConnection(dbConnect); 


        // I added the creation MySQLConnect object after I was getting an error that the database was closed when trying to insert. 
     dbConnect = new MySQLConnect(); 
    } 
    return "end of routine"; 
} 

//Extract comma delimited message elements into an array 
private static ArrayList<String> getMessageElements(String rcvString) { 
    StringTokenizer st = new StringTokenizer(rcvString, ","); 

    ArrayList<String> al = new ArrayList<String>(); 

    while (st.hasMoreElements()) { 
     String messageElement = (String) st.nextElement(); 
     al.add(messageElement); 

    } 



    return al; 
} 

}

這將運行約8小時,然後我得到以下錯誤:在線程主java.lang.StackOverflowError的

異常

例外: java.lang.outofmemoryerror從主線程中的uncaughtexceptionhandler拋出

此前,我沒有重新實例化MySQLConnect對象的尾部呃數據庫被關閉了。問題是我收到數據庫連接已關閉的錯誤,但我的程序仍在嘗試執行jdbc插入。 jdbc插入首先檢查是否有實例化的連接,如果沒有實例化它。這從MySQLConnect類代碼如下所示:在未來的無限期和發生錯誤時寫入數據庫甚至

PreparedStatement prep = null; 

    if (connection == null) { 
     connection = this.instantiateConnection(); 
    } 

    try { 

     prep = connection 
       .prepareStatement("insert into MyTable (UDPMessage)" 
         + "values (?);"); 

     prep.setString(1, udpMessage); 




     prep.addBatch(); 

     prep.executeBatch(); 

如何建築師這個過程中要正確處理UDP消息?

另外如何解決在處理數據時發生異常時重新實例化MySQLConnect類時出現內存不足錯誤?

如果在發生異常後實例化這個類是不正確的,我該如何重新實例化與數據庫的連接以繼續處理數據?

感謝您的幫助!

回答

1

您還沒有在代碼中的任何位置設置布爾值loopRecvfalse,導致無限循環(條件始終解析爲true)。無限/遞歸循環持續填充堆棧,但不要刪除任何堆棧幀並導致StackOVerflowError

0

如果你不擔心同步性,爲什麼不把循環內容放在另一個線程中。執行該線程一次,然後它被丟棄。然後在無限循環中,創建另一個線程並執行它。這些線程將自行處置並從堆棧中移除。

1

對於循環終止

while (loopRecv) { 
... 
} 

你應該標記loopRecv=false;地方是不區分。