Boa tarde pessoal, criei um servidor de socket que suporta multiplos clientes. Está funcionando direitinho.
O problema é que a cada conexão recebida, a memória usada pelo servidor aumenta (É possivel ver no gerenciador de tarefas).
É como se a thread nunca morresse…
Tirei fora a parte do socket, deixei apenas o servidor recebendo a conexão e iniciando uma Thread (vazia)
e adivinha só, o problema continua… a memória gasta é menor, mas ainda assim continua aumentando.
Esse comportamento é normal ? Há uma forma de evitar isso ?
Pois chega uma hora que ele atinge o limite, e para de receber conexões.
segue código do multi thread.
publicclassMiddleServer{publicstaticvoidmain(String[]args)throwsIOException,InterruptedException{try{ServerSocketlistener=newServerSocket(4444);while(true){listener.accept();Threadt=newThread();t.start();}}catch(IOExceptionioe){System.err.println("Could not listen on port"+ioe);System.exit(-1);}}}
Esse comportamento não é normal. Para descobrir gargalos e problemas de performance, use um profiler. Eu recomendaria usar o do Netbeans ou o Visual VM, que acompanha o próprio Java.
V
ViniGodoy
Nesse caso, talvez haja problema pois você nunca está dando close() nos sockets recebidos no accept.
E
edinhomustaine
O close fica na outra classe… segue codigo completo:
Multi Thread:
importjava.io.IOException;importjava.net.ServerSocket;importjava.net.Socket;publicclassMiddleServer{publicstaticvoidmain(String[]args)throwsIOException,InterruptedException{try{ServerSocketlistener=newServerSocket(4444);Socketserver;while(true){server=listener.accept();KKMultiServerThreadconn=newKKMultiServerThread(server);Threadt=newThread(conn);t.start();}}catch(IOExceptionioe){System.err.println("Could not listen on port"+ioe);System.exit(-1);}}}
Quanto ao profile, eu tentei utilizar seguindo esse tutorial.
Parece que realmente tem algo errado, mas não consigo entender o que. Ele aponta para umas classes nativas.
:?
E
entanglement
Conselho: em vez de ficar criando threads à toa, use um pool de threads. Procure por ThreadPoolExecutor:
importjava.io.IOException;importjava.net.ServerSocket;importjava.net.Socket;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;publicclassMiddleServer{publicstaticvoidmain(String[]args)throwsIOException,InterruptedException{try{ExecutorServiceexec=Executors.newFixedThreadPool(50);ServerSocketlistener=newServerSocket(Constantes.PORTA_CRIPTO);Socketserver;booleanquebraLoop=false;while(!quebraLoop){server=listener.accept();exec.execute(newKKMultiServerThread(server));}}catch(IOExceptionioe){System.err.println("Could not listen on port"+ioe);System.exit(-1);}}}
mas o problema continua…
no gerenciador de memória, a aplicação consome 9.032 kb.
e vai aumentando conforme vai chegando conexões… depois de umas 10 conexões chega a estar com 10.228 kb
eu sei que é coisa mínima, mas com o tempo chega ao limite e trava tudo.
pra quebrar o galho, estou reiniciando a aplicação toda segunda-feira.
E
entanglement
Ou seja, você descobriu que o problema de uso de memória não é com threads.
Só por curiosidade, você está usando ObjectInputStream/ObjectOutputStream com sockets?
mas nesse exemplo não coloquei, e o problema continua.
será que você poderia testar o código que postei antes do ThreadPool ? são 2 clases apenas.
eu executo o server, que fica ouvindo a porta 4444, e acesso essa porta via browser. deixo o gerenciador de tarefas aberto e percebo o consumo de memória aumentando conforme as conexões. eu sou realmente muito iniciante em java, por isso, não creio que eu vá conseguir descobrir se há algo errado ou se esse é um comportamento padrão.
E
entanglement
Não estou me referindo a BufferedReader e sim a ObjectInputStream / ObjectOutputStream (a menos que você tenha misturado o BufferedReader/PrintWriter com ObjectInputStream/ObjectOutputStream, o que não é nem um pouco saudável )
E
edinhomustaine
entanglement:
Não estou me referindo a BufferedReader e sim a ObjectInputStream / ObjectOutputStream (a menos que você tenha misturado o BufferedReader/PrintWriter com ObjectInputStream/ObjectOutputStream, o que não é nem um pouco saudável )
desculpe minha falta de atenção…
não utilizo ObjectInputStream / ObjectOutputStream.
E
entanglement
Ufa, um problema a menos.
Pois bem, o aumento da memória, no seu caso, só pode ser diagnosticado com uma ferramenta (como o jhat ou o Eclipse Memory Analyzer, http://www.eclipse.org/mat/ )
O que você faz, normalmente:
a) Captura um instantâneo da memória consumida por sua aplicação depois que você criou uma 2 ou 3 conexões
b) Captura outro instantâneo depois que você criou mais outras conexões (digamos umas 1000) mas depois você as encerrou
c) Compara os instantãneos e vê que objetos estão ficando “presos”
E
edinhomustaine
Eu cheguei a fazer isso usando o VisualVM, nativo do JDK.
Não consegui nenhuma pista… vou testar com o Eclipse Memory Analyzer.
E
edinhomustaine
Moçada, fiz o teste o com o Eclipse Analyser, e nada !
Copiei e colei o exemplo do site da Oracle e coloquei pra rodar (o do fim da página):
Uma vantagem de usar um pool com tamanho fixo é que é trivial rejeitar uma conexão se um limite for alcançado
EDIT - não olhei que você já estava usando um pool de threads
De qualquer forma, sempre que você receber uma conexão e a encapsular em um BufferedAlgumaCoisa, não se esquecer de fechar o BufferedAlgumaCoisa também - só um BufferedAlgumaCoisa já reserva um buffer de 8KB por default, que só é liberado quando ele é explicitamente fechado.
E
entanglement
Muitos dos exemplos do Java Tutorial não são para serem usados no esquema “copiar e colar em um sistema em produção”.
Muitas vezes eles não são “exemplos de melhores práticas”.
São apenas “exemplos de como uma determinada coisa pode ser usada”, ou seja, você tem de entender o que está sendo feito, para você poder fazer algo melhor.
Note que eles:
a) Não fazem tratamento completo de exceções (senão o exemplo ficaria muito poluído com tratamento de exceções etc.)
b) Usam certas coisas (como DefaultTableModel) que só são usados em exemplos, não em sistemas reais.