0

I get this error basically less then an hour after i fire this nohup java -cp server.jar:mysql-connector.jar com.server.test.EchoMulti &. The error:

Exception in thread "main" java.lang.OutOfMemoryError: unable to create new native thread    
    at java.lang.Thread.start0(Native Method)                                            
    at java.lang.Thread.start(Unknown Source)                                            
    at com.server.test.EchoMulti.main(EchoMulti.java:14)

I'm new to servers and Java. This is the first thing I did on a server and in Java and it's a multiplayer for Android game. The game is doing quite good so there are many people trying to play the multiplayer. I already fixed the mySQL max_connections but now i got whis problem. I would also like to know if there is a way to restart process automatically when it gets an error that causes a crach. And a way to automatically start it on reboot.

The EchoMulti class that's causing it:

package com.server.test;
import java.net.*;
import java.io.*;

public class EchoMulti {

    public static void main(String[] args) throws IOException {

        int portNumber = 25003;
        boolean listening = true;

        try (ServerSocket serverSock = new ServerSocket(portNumber)) { 
            while (listening) {
                new EchoServer(serverSock.accept()).start();
            }
        } catch (IOException e) {
            System.err.println("Could not listen on port " + portNumber);
            System.exit(-1);
        }
    }

}

The EchoServer class:

package com.server.test;
import java.net.*;
import java.io.*;
import java.sql.*;
import java.lang.Thread;


public class EchoServer extends Thread {
     private Socket sock = null;

     public EchoServer(Socket sock) {
         super("EchoServer");
         this.sock = sock;
     }

public void run(){
    String url = "jdbc:mysql://IP:3306/DB";
    String username = "USER";
    String password = "PASSWORD";
    Connection con = null;
    Statement sta = null;
    ResultSet resultSet = null;

    try {
        //System.out.println("Connecting database...");
        con = DriverManager.getConnection(url, username, password);
        //System.out.println("Database connected!");
    } catch (SQLException e) {
        throw new RuntimeException("Cannot connect the database!", e);
    }

    try (
        PrintWriter out = new PrintWriter(sock.getOutputStream(), true);                   
        BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
    ) {
        String inputLine;
        while ((inputLine = in.readLine()) != null) {
            if(inputLine.equalsIgnoreCase("get")){
                    SEND SOMETHING
            } else {
                String catched[] = inputLine.split("\\;");
                if(catched[0].equalsIgnoreCase("sub")){
                    SEND SOMETHING
                } else if(catched[0].equalsIgnoreCase("res")){
                    SEND SOMETHING
                }
            }
        }
    } catch (IOException e) {
        System.out.println("Exception caught when trying to listen on port 25003 or listening for a connection");
        System.out.println(e.getMessage());
    } finally {
        //System.out.println("Closing the connection.");
        if (con != null) try { con.close(); } catch (SQLException ignore) {}
        try { sock.close(); } catch (IOException ignore) {} finally {}
    }
}
public void close() throws IOException {
    if (sock != null) sock.close();
}
}

1 Answers1

0

You can also have a memory leak somewhere, or something preventing the correct garbage collection of used memory.

I would do the following three things.

Modify the EchoServer class You can add a static member to understand if, when the crash occurs, the number of existing thread in memory is the one you expect (they should be as many as the connected players).

public class EchoServer extends Thread {
     private Socket sock = null;
     private static Integer CONNECTED = 0;
     public EchoServer(Socket sock) {
         try{
         super("EchoServer");
         this.sock = sock;
         CONNECTED++;
         } catch (Exception ex)
         {
            Logger.getLogger(EchoServer.class.getName()).log(Level.SEVERE, "Currently CONNECTED: "+CONNECTED);
         }
     }

     .... your stuff here

     @Override
     public void finalize(){
         super.finalize();  
         CONNECTED--;
     }
}

If have more threads than connected players something is wrong.

Use a profiler Use a profiler to observe the memory usage and identify bottlenecks. Also be sure there aren't "strange" objects surviving generations or that the memory is not increasing over time without an increment of the players. NetBeans has a nice profiler that can be connected via TCP to live apps too.

Use -Xmx Use java -Xmx1g to launch the server.

elbuild
  • 4,869
  • 4
  • 24
  • 31
  • I checked the app with Java VisualVM. Here are the results: [link](http://pixelperfectdude.com/skijump/memory.jpg). The error occurs when the threads start to go down. Without the jstatd running it reaches about 1000-1200. It seems like the memory is dropping time to time. When i run free -m it's almost full. Here are the logs of the errors [link](http://pixelperfectdude.com/skijump/logs.rar). – Dariusz Pietrala Jan 26 '14 at 12:32
  • Your application is not crashing for insufficient memory...it the JVM itself that is crashing. This can happen both for a bug in your app or in case the resources of the system are heavily overused. In your case I suspect a bug since the heap in your profiling session is only 256Mb and you said you have 1G of RAM. Have a look to http://stackoverflow.com/questions/6344546/java-6-update-25-vm-crash-insufficient-memory and check if it fits you case. – elbuild Jan 26 '14 at 13:11
  • Anyway try to use Xmx and moreover Xss to control the thread stack size. – elbuild Jan 26 '14 at 13:12
  • I didn't have this earlier but now i get this when the error appears: `Resource counter_cpu_share_used red alert on environment mydomain.pl current value: 87 soft limit: 85 hard limit: 95` – Dariusz Pietrala Jan 26 '14 at 13:32
  • That log seems Plesk related...I really don't know :( – elbuild Jan 26 '14 at 13:40
  • It's from the Parallels Panel, I thought it was related somehow. I managed to get to 2000 by changing -Xss512k. I also had some problems with mysql when it reached ~2000 but i changed the `open_files_limit` to 65536 and it fixed it. I'm starting to believe that physical memory is to low. The worst thing is that I can't reach the moment when some of the connections end. There's too much people playing and I think 1G is to low :( – Dariusz Pietrala Jan 26 '14 at 18:18
  • Yes 1G is really nothing for server side stuff nowadays...If you think that my Nexus 5 has 2 GB :D. Move to a new server if you can. OVH has nice low cost servers. – elbuild Jan 26 '14 at 19:46
  • I managed to rebuild my client side and now it's ok. The threads are killed more often so I don't get so many in one time. But I would like to know how to: 1. Set a maximum life time of a thread 2. Create a threadpool of max ~1000 threads. – Dariusz Pietrala Jan 28 '14 at 21:45