У меня есть небольшая сетевая игра, которую я собираюсь изучить в сети 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);
}
}
}
Нет, это невозможно, вы не можете утечки памяти в java!/fanboyism – Cruncher
100% -ый процессор указывает на то, что там где-то есть большая спин-блокировка. Возможно, метод output(). Я бы привязал Thread.sleep (10); там, и посмотреть, немного ли он немного успокоит процессор. – Kayaman
Внесение сна (10) на самом деле действительно сильно повлияло на процессор. Он снизился с 90-100% до ~ 50%. Что касается кучи, она также сильно изменилась, но через несколько минут размер кучи начинает складываться линейно. Я понятия не имею, где утечка памяти может быть, но я буду продолжать искать. –