Я пытаюсь построить сервер, но использование пула потоков привело к утечке памяти, которая приводит к переполнению моей кучи.
Мой сервер создает два основных потока из основного потока: Acceptor и Consumer. Я новичок в JProfiler, но, похоже, он очень четко указал мне на приведенный ниже код (Acceptor) как на виновника.
Поток Acceptor принимает новые подключения от клиентов. После принятого вызова для обработки соединения используется новый поток из пула потоков.
public class AcceptorThread implements Runnable{
LinkedBlockingQueue<LinkedList<Log_Message>> queue = null;
public AcceptorThread(LinkedBlockingQueue<LinkedList<Log_Message>> queue){
this.queue = queue;
}
@Override
public void run() {
ExecutorService acceptors = Executors.newCachedThreadPool();
ServerSocket socket = null;
try {
socket = new ServerSocket(44431);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
while(!init_LogServer.isStopped()){
Socket connectionSocket = null;
try {
connectionSocket = socket.accept();
} catch (IOException e) {
e.printStackTrace();
}
init_LogServer.addList();
System.out.println("Accepted New List: " + init_LogServer.getListCount());
Runnable worker = new List_Acceptor(connectionSocket, queue);
acceptors.execute(worker);
}
}
}
Новый поток из пула потоков получает связанный список объектов, этот список добавляется в очередь и поток завершается. Насколько я понимаю, после завершения приведенного ниже кода поток завершится, указанный ниже объект будет собран сборщиком мусора, и поток повторно войдет в пул потоков для повторного использования. Я не вижу каких-либо очевидных небольших утечек памяти, поэтому я предполагаю, что происходит то, что приведенный ниже класс никогда не собирается сборщиком мусора, что приводит к созданию кучи, это правильно? Как я могу уничтожить указанный ниже объект после добавления полученного списка в очередь?
public class List_Acceptor implements Runnable{
Socket socket = null;
private LinkedList<Log_Message> lmList = null;
private LinkedBlockingQueue<LinkedList<Log_Message>> queue = null;
private String dumpMessage = null;
public List_Acceptor(Socket socket, LinkedBlockingQueue<LinkedList<Log_Message>> queue){
this.queue = queue;
this.socket = socket;
}
@Override
public void run() {
ObjectInputStream input = null;
try {
input = new ObjectInputStream(socket.getInputStream());
} catch (IOException e3) {
// TODO Auto-generated catch block
e3.printStackTrace();
}
Object received = null;
try {
received = input.readObject();
} catch (ClassNotFoundException | IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
lmList = (LinkedList<Log_Message>) received;
} catch (Exception e1) {
//e1.printStackTrace();
System.out.println("Received DumpLog");
dumpMessage = (String) received;
System.out.println("Dump: "+dumpMessage);
init_LogServer.stop();
e1.printStackTrace();
}
//close socket
try {
socket.close();
input.close();
} catch (IOException e2) {e2.printStackTrace();}
try {
queue.put(lmList);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
РЕДАКТИРОВАТЬ: я узнал, что, по-видимому, когда экземпляр объекта/класса создается через поток, как я это делаю с пулом потоков, GC не может очистить этот объект. Это кажется вероятной причиной утечки памяти и, возможно, моей проблемой. Имея это в виду, завтра я переработаю дизайн, чтобы AcceptorTread выполнял необходимые шаги для помещения полученного списка в очередь, это должно быть медленнее, но предотвратит проблему с кучей. Имеет ли это смысл?