Como fazer o perfil de memória em Java?

Ainda estou a aprender as cordas de Java. desculpa se há uma resposta óbvia para isto. Eu tenho um programa que está tomando uma tonelada de memória e eu quero descobrir uma maneira de reduzir o seu uso, mas depois de ler muitas perguntas eu tenho a idéia de que eu preciso provar onde o problema está antes de começar a otimizá-lo.

Então aqui está o que eu fiz, eu adicionei um ponto de ruptura para o início do meu programa e o executei, então eu comecei visualVM e tinha o perfil da memória(eu também fiz a mesma coisa em netbeans apenas para comparar os resultados e eles são os mesmos). Meu problema é que eu não sei como lê-los, eu tenho a área mais alta apenas dizendo {[[0]} e eu não posso ver qualquer código ou qualquer coisa(o que faz sentido porque visualvm está conectando ao jvm e não pode ver a minha fonte, mas netbeans também não me mostra a fonte como ele faz ao fazer o perfil de cpu).

basicamente o que eu quero saber é qual variável (e espero que mais detalhes como em que método) toda a memória está a ser usada para que eu pode concentrar-se em trabalhar lá. Há uma maneira fácil de fazer isto? Eu agora estou usando eclipse e java para desenvolver (e instalado visualVM e netbeans especificamente para o perfil, mas estou disposto a instalar qualquer outra coisa que você sente faz este trabalho feito).

EDIT: idealmente, estou à procura de algo que pegue em todos os meus objectos e os separe por tamanho(para que possa ver qual deles está a monopolizar a memória). Actualmente devolve informações genéricas como string [] ou int [], mas eu quero saber qual o objecto está a referir-se para que eu possa trabalhar para que o seu tamanho seja mais optimizado.

Author: Error_404, 2012-04-11

5 answers

As cadeias de caracteres são problemáticas

Basicamente em Java, String as referências (coisas que usam char[] nos bastidores ) dominarão a maioria dos negócios aplicações de memória. A forma como são criados determina a quantidade de memória que consomem na JVM.

Só porque são fundamentais para a maioria das aplicações empresariais como um tipo de dados, e também são uma das mais famintas de memória. Isto não é apenas uma coisa Java, {[[0]} os tipos de dados ocupam muitos memory in pretty much every language and run time library, because at the least they are just arrays of 1 byte per character or at the worse (Unicode ) they are arrays of multiple bytes per character.

Uma vez, ao traçar o perfil da utilização do CPU numa aplicação web que também tinha uma dependência do Oracle JDBC, descobri que StringBuffer.append() dominava os ciclos do CPU por muitas ordens de magnitude sobre todas as outras chamadas de método combinadas, muito menos qualquer outra chamada de método único. O motorista do JDBC fez muitas e muitas coisas. de manipulação, uma espécie de troca de usar PreparedStatements para tudo.

O que você está preocupado com você não pode controlar, não diretamente de qualquer maneira

O que você deve focar é o que em seu controle, que é certificar-se de que você não mantém referências por mais tempo do que você precisa, e que você não está duplicando as coisas desnecessariamente. As rotinas de coleta de lixo em Java são altamente otimizadas, e se você aprender como seus algoritmos funcionam, você pode ter certeza de que o seu o programa se comporta da maneira ideal para que esses algoritmos funcionem.

Java Heap Memory não é como a memória gerenciada manualmente em outras linguagens, essas regras não se aplicam

O que são considerados fugas de memória noutras línguas não são a mesma coisa/causa raiz como em Java com o seu sistema de recolha de lixo.

O mais provável é que na memória Java não seja consumida por um único objeto uber que está vazando ( referência balançando em outros ambientes ).

([19]} é muito provável que haja lotes de dotações mais pequenas por causa de StringBuffer/StringBuilder Os objectos não dimensionados de forma apropriada nas primeiras instantâneas e que, em seguida, têm de crescer automaticamente as matrizes char[] para manter as chamadas subsequentes append(). Estes objetos intermediários podem ser mantidos por mais tempo do que o esperado pelo coletor de lixo por causa do escopo em que eles estão e muitas outras coisas que podem variar em tempo de execução.

Exemplo: o coletor de lixo pode decidir que lá são candidatos, mas porque ele considera que há muita memória ainda a ser tido que pode ser muito caro tempo sábio para puxá-los para fora nesse ponto no tempo, e ele vai esperar até que a pressão da memória fica maior.

O coletor de lixo é muito bom agora, mas não é magia, se você está fazendo coisas degeneradas, isso fará com que ele não funcione de forma otimista. Há muita documentação na internet sobre as configurações do coletor de lixo para todas as versões do JVMs.

Estes objectos não referenciados podem simplesmente não ter atingido o momento em que o coletor de lixo pensa que precisa deles para que eles sejam apagados da memória, ou pode haver referências a eles mantidos por algum outro objeto ( List ) por exemplo, que você não percebe ainda pontos para esse objeto. Isto é o que é mais comumente referido como um vazamento em Java, que é um vazamento de referência mais especificamente.

Exemplo: se sabe que precisa de construir um 4K String usando um StringBuilder crie - o com new StringBuilder(4096); não o padrão, que é como 32 e irá imediatamente começar a criar lixo que pode representar muitas vezes o que você acha que o objeto deve ser tamanho sábio.

Você pode descobrir quantos tipos de objetos estão instanciados com VisualVM, isso lhe dirá o que você precisa saber. Não vai haver uma grande luz piscando que aponta para uma única instância de uma única classe que diz: "Este é o grande consumidor de memória!", isto é, a menos que existe apenas uma instância de alguns char[] em que você está lendo algum arquivo massivo, e isso também não é possível, porque muitas outras classes usam char[] internamente; e então você praticamente já sabia disso.

Não vejo nenhuma menção OutOfMemoryError

Você provavelmente não tem nenhum problema em seu código, o sistema de coleta de lixo pode não estar sendo colocado sob pressão suficiente para chutar e desalocatar objetos que você pensa deveria ser a limpar. O que achas que é um problema provavelmente não é, a não ser que o teu programa esteja a falhar com OutOfMemoryError. Isto não é C, C++, Objective-C, ou qualquer outra linguagem de gerenciamento de memória manual / tempo de execução. Você não pode decidir o que está na memória ou não no nível de detalhe que você está esperando que você deve ser capaz de.
 24
Author: feeling abused and harassed, 2012-04-11 16:52:16

InJProfiler , você pode ir para o heap walker e ativar a maior vista de objetos. Você vai ver os objetos a reter mais memória. Memória "retida" é a memória que seria libertada pelo coletor de lixo se você removesse o objeto.

Você pode então abrir os nós de objetos para ver a árvore de referência dos objetos retidos. Aqui está uma imagem da maior vista de objectos:

enter image description here

AVISO: A minha empresa desenvolve a JProfiler

 8
Author: Ingo Kegel, 2012-04-15 14:54:49

Java JDK vem com JVisualVM sob a pasta bin, logo que o seu servidor de aplicações (por exemplo, esteja a correr), você poderá executar o visualvm e ligá-lo ao seu localhost, que lhe irá fornecer a alocação de memória e permitir-lhe-á executar o heap dump

enter image description here

Para mais detalhes sobre como activar: http://sysdotoutdotprint.com/technologies/java/6

 2
Author: mel3kings, 2018-04-04 05:18:23

Se usar o visualVM para verificar o seu uso de memória, ele centra-se nos dados, não nos métodos. Talvez os seus grandes dados de char sejam causados por muitos valores de String? A menos que você esteja usando recursão, os dados não serão de variáveis locais. Então você pode se concentrar nos métodos que insiram elementos em grandes estruturas de dados. Para descobrir que afirmações precisas causam a sua "fuga de memória", sugiro-lhe adicionalmente {[[2]}

 0
Author: DaveFar, 2012-04-11 15:32:48