Процессу Java не хватает памяти при создании потока в CentOS 6

Я получаю эту ошибку в основном менее чем через час после того, как я запускаю этот nohup java -cp server.jar:mysql-connector.jar com.server.test.EchoMulti &. Ошибка:

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)

Я новичок в серверах и Java. Это первое, что я сделал на сервере и на Java, и это многопользовательская игра для Android. Игра идет довольно хорошо, поэтому многие люди пытаются играть в мультиплеер. Я уже исправил mySQL max_connections, но теперь у меня возникла проблема. Я также хотел бы знать, есть ли способ перезапустить процесс автоматически, когда он получает ошибку, вызывающую сбой. И способ автоматического запуска при перезагрузке.

Класс EchoMulti, который вызывает это:

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

}

Класс эхосервера:

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

person Dariusz Pietrala    schedule 25.01.2014    source источник
comment
Попробуйте увеличить оперативную память для вашего Java-приложения.   -  person Luiggi Mendoza    schedule 25.01.2014
comment
У меня VPS 1Ггц, 1Гб ОЗУ и 50Гб места. Может быть, я должен создать файл подкачки?   -  person Dariusz Pietrala    schedule 25.01.2014
comment
Вы были правы насчет оперативной памяти :) Но мне удалось уменьшить номер потока.   -  person Dariusz Pietrala    schedule 29.01.2014


Ответы (1)


У вас также может быть утечка памяти где-то или что-то, что мешает правильной сборке мусора используемой памяти.

Я бы сделал следующие три вещи.

Измените класс EchoServer. Вы можете добавить статический член, чтобы понять, соответствует ли количество существующих потоков в памяти при сбое ожидаемому (их должно быть столько же, сколько подключенных игроков).

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

Если тредов больше, чем подключенных игроков, что-то не так.

Используйте профилировщик Используйте профилировщик, чтобы наблюдать за использованием памяти и выявлять узкие места. Также убедитесь, что нет «странных» объектов, переживших поколения, или что память не увеличивается со временем без увеличения количества игроков. NetBeans имеет хороший профилировщик, который также можно подключить через TCP к живым приложениям.

Используйте -Xmx Используйте java -Xmx1g для запуска сервера.

person elbuild    schedule 25.01.2014
comment
Я проверил приложение с помощью Java VisualVM. Вот результаты: ссылка. Ошибка возникает, когда потоки начинают опускаться. Без запущенного jstatd достигает 1000-1200. Кажется, что память время от времени сбрасывается. Когда я запускаю free -m, он почти полон. Вот журналы ошибок ссылка. - person Dariusz Pietrala; 26.01.2014
comment
Ваше приложение не дает сбой из-за нехватки памяти... это сама JVM, которая дает сбой. Это может произойти как из-за ошибки в вашем приложении, так и из-за чрезмерного использования ресурсов системы. В вашем случае я подозреваю ошибку, поскольку куча в вашем сеансе профилирования составляет всего 256 МБ, а вы сказали, что у вас 1 ГБ ОЗУ. Взгляните на stackoverflow.com/questions/6344546/ и проверьте, подходит ли он вам. - person elbuild; 26.01.2014
comment
В любом случае попробуйте использовать Xmx и, кроме того, Xss для управления размером стека потоков. - person elbuild; 26.01.2014
comment
Раньше у меня этого не было, но теперь я получаю это, когда появляется ошибка: Resource counter_cpu_share_used red alert on environment mydomain.pl current value: 87 soft limit: 85 hard limit: 95 - person Dariusz Pietrala; 26.01.2014
comment
Этот журнал кажется связанным с Plesk... Я действительно не знаю :( - person elbuild; 26.01.2014
comment
Это из панели Parallels, я думал, что это как-то связано. Мне удалось добраться до 2000, изменив -Xss512k. У меня также были некоторые проблемы с mysql, когда он достиг ~ 2000, но я изменил open_files_limit на 65536, и это исправлено. Я начинаю верить, что физической памяти недостаточно. Хуже всего то, что я не могу дойти до момента, когда часть соединений обрывается. Слишком много людей играет, и я думаю, что 1G - это мало :( - person Dariusz Pietrala; 26.01.2014
comment
Да, 1G в наши дни действительно ничто для серверной части... Если вы думаете, что у моего Nexus 5 2 ГБ :D. Если есть возможность, перейдите на новый сервер. У OVH хорошие недорогие серверы. - person elbuild; 26.01.2014
comment
Мне удалось восстановить мою клиентскую часть, и теперь все в порядке. Потоки убиваются чаще, поэтому я не получаю так много за один раз. Но я хотел бы знать, как: 1. Установить максимальное время жизни потока 2. Создать пул потоков максимум ~ 1000 потоков. - person Dariusz Pietrala; 29.01.2014