2013-11-13 4 views
2

У меня есть небольшая сетевая игра, которую я собираюсь изучить в сети Java, и мне нужно немного понять, с чем связана моя программа. Моя программа сервера высвобождает кучу и сжигает 100% CPU. Я уверен, что у меня есть основной новичок в кодексе, и мне интересно, будет ли кто-нибудь так любезным, чтобы указать на меня, и, возможно, подробно, почему это такая ужасная практика.Java-серверная программа, максимизирующая кучу, сжигание CPU

В основном задача класса сервера заключается в том, чтобы ждать в socket.accept() для работы с новыми клиентами. Каждый клиент оттуда получает свой собственный ConnectionThread (который имеет дело с вводом) и подключенный OutputStream (который обрабатывает выходные данные). Я знаю, что это может быть расточительным для больших приложений, но с сервером, работающим вместе с тремя клиентами (которые настроены на пропускание рендеринга и только отправляют данные через сокет каждые ~ 20 мс для ввода и вывода), он готовит процессор и сервер переполняет стек.

У меня есть класс пакетов, который преобразует данные в строку для отправки, а получатель декодирует его обратно в пакет. Я подозреваю, что у меня есть несколько пакетов, которые лежат слишком долго, но я не вижу, где. Если это не пакеты, я уверен, что у меня есть НЕКОТОРЫЙ вид неконтролируемого роста экспоненциальных объектов.

Ниже приведены некоторые фрагменты соответствующего кода. Я счастлив предоставить больше, если проблема в другом месте.

Просто для справки, вот полный код: https://github.com/taylorrobert/ProjectM2O

Сервер:

public Server() { 
    network = new NetworkManager(this); 
    network.setConnectionCounter(0); 
    entityManager = new EntityManager(this); 
    setListenState(true); 

    try { 
     serverSocket = new ServerSocket(PORT); 

    } catch (IOException e) { 
     System.out.println("Error in server constructor."); 
     System.exit(1); 
    } 
} 

public void listen() { 

     System.out.println("Current connectionCounter: " + network.getConnectionCounter()); 
     while (shouldListen) { 
      ConnectionThread conn = null; 

      try { 
       conn = new ConnectionThread(serverSocket, this); 
      } 
      catch (Exception e) { 
       System.out.println("____Error constructing ConnectionThread. Could there be another instance of the server running?"); 
       e.printStackTrace(); 
       System.exit(1); 
      } 

      (new Thread(conn)).start(); 


      System.out.println("Connection count: " + network.getConnectionCounter()); 
     } 
    } 

ConnectionThread:

public ConnectionThread(ServerSocket s, Server ser) { 
    resetTimer(); 
    setActiveState(false); 
    server = ser; 

    //This UUID becomes the client's controllable player ID 
    //and the ID of this ConnectionThread. 
    connectionID = String.valueOf(UUID.randomUUID()); 

    try { 
     socket = s.accept(); 
     System.out.println("Socket ID " + connectionID + " established on: " + socket); 
    } catch (IOException e) { 
     System.out.println("Error in ConnectionThread. Is there a server already running on this port?"); 
    } 
    init(); 
} 

public void init() { 
     try { 
      out = new PrintWriter(socket.getOutputStream(), true); 
      in = new BufferedReader(new InputStreamReader(socket.getInputStream())); 

     } 
     catch (IOException e) { 
      System.out.println("Error in intializing I/O streams."); 
      System.exit(1); 
     } 

     //Create the output thread 
     OutputStream outputHandler = new OutputStream(this); 
     new Thread(outputHandler).start(); 


     //Get the client up to date on all relevant data 
     server.getEntityManager().addPlayerEntity(getConnectionID()); 
     server.getNetwork().pushClientInitState(getConnectionID(), this); 
     server.getNetwork().addConnection(this); 
     server.getNetwork().notifyClientsAboutNewPlayer(getConnectionID()); 
     int s = server.getNetwork().getConnections().size(); 
     server.getNetwork().sendConsoleMessage("Players online: " + s, this); 

    } 

public void run() { 
    setActiveState(true); 
    System.out.println("Running ConnectionThread..."); 
    while (isActive()) { 


     //System.out.println("Entity size: " + server.getEntityManager().getEntities().size()); 
      String op = readInputStream(); 

      if (op.equals("")) continue; 
      Packet packet = Packet.populateNewPacketFromString(op); 
      try { 
       incomingOpQueue.put(packet); 
      } catch (InterruptedException e) { 
       System.out.println("Server failed to add packet to outgoing queue!"); 
      } 
      //Take all packets off the incoming queue and execute them in order 
      while (incomingOpQueue.size() > 0) { 
       Packet p = incomingOpQueue.poll(); 
       PacketExecutor.executePacket(server, p, this); 


      } 
    } 
} 

public String readInputStream() { 
    String msg = ""; 

    try { 
     msg = in.readLine(); 
     msg = msg.replace("\n", ""); 
     msg = msg.trim(); 
    } catch (IOException e) { 
     return ""; 
    } 
    return msg; 

} 

OutputStream:

public void output() { 
    while (parentCT.isActive()) { 
     UnitTester.updateAllEntityLocationsToAllClients(parentCT, parentCT.server.getEntityManager().getEntities()); 
     while (parentCT.getOutgoingOpQueue().size() > 0) { 
      String packet = (parentCT.getOutgoingOpQueue().poll().getString()); 
      if (packet.equals("")) continue; 
      //System.out.println("Sending " + packet + " to " + parentCT.getConnectionID()); 
      parentCT.getOutput().println(packet); 

     } 

    } 
} 
+0

Нет, это невозможно, вы не можете утечки памяти в java!/fanboyism – Cruncher

+0

100% -ый процессор указывает на то, что там где-то есть большая спин-блокировка. Возможно, метод output(). Я бы привязал Thread.sleep (10); там, и посмотреть, немного ли он немного успокоит процессор. – Kayaman

+0

Внесение сна (10) на самом деле действительно сильно повлияло на процессор. Он снизился с 90-100% до ~ 50%. Что касается кучи, она также сильно изменилась, но через несколько минут размер кучи начинает складываться линейно. Я понятия не имею, где утечка памяти может быть, но я буду продолжать искать. –

ответ

2

Вы, наверное, необходимо сделать shouldListen неустойчивым. В противном случае, есть все шансы, что его значение будет кэшироваться, и установка его в false в каком-то другом потоке не будет иметь никакого значения. Вы : устанавливаете его на ложное право, так что основной цикл просто не делает много и много потоков, пока он не выгрузит кучу и не сгорит CPU?

+1

Я ничего не вижу в его фрагменте, который устанавливает 'shouldListen' в false. –

+0

Действительно. Он будет блокироваться на serverSocket.accept() в любом случае, поэтому это ограничивающий фактор. – Kayaman

+0

Как сказал Кайаман, внутри конструктора ConnectionThread используется метод ServerSocket.accept(), который блокирует создание новых потоков, пока он не может быть сопряжен с клиентом. –

Смежные вопросы