PermGen Space: Tem como alocar e desalocar dinamicamente esse espaço?

Olá pessoal,

não sei se esse é o melhor lugar para postar isso (em Java Avançado), se estiver em lugar errado, gostaria que algum modera movesse.

O problema é o seguinte, eu tenho um cache de consultas SQL na máquina virtual, e quando eu aloco consultas maiores (mas sempre limito o tamanho delas), ou uma quantidade maior de consultas, ele dá erro de permgen space. Até aí tudo bem, mas tenho 2 dúvidas.

A primeira é se existe alguma maneira para o tomcat alocar e liberar o PermSize dinamicamente (ou se ele já faz isso automaticamente).

A segunda, é se eu deixo ele com um maxpermsize muito elevado (digamos, 50% da memória principal total), quando o resto da máquina virtual precisar ele vai permitir que seja usado essa memória que ele precisa.

Cara, se tem não sei, mas não acho que seja a melhor solução fazer isso.

Uma vez que vc consiga fazer isso, quanto mais consultas vierem, mais alocações dinâmicas aconteceriam e uma hora ou outra iria estourar novamente.

Uma boa seria vc paginar sua consulta. Fazer pequenas consultas e ir exibindo e tratando os valores a medida do necessário.

então, eu só mantenho na memória as últimas 30 consultas feitas. Sempre limitando a quantidade de registros que ela me retorna, então, não é um memory leak, é que estou usando mais espaço na memória mesmo.

Quando entra uma 31º consulta, diferente das 30 primeiras, eu libero uma e coloco outra.

Obs: limitando o cache para somente 15 consultas, não me dá erro.

Olá,

eu já tive diversos problemas de memory leak de objetos que pensava que não estava sendo referenciado e ele ainda estava preso… principalmente em threads…

Se você implementou uma LRU de tamanho fixo ou uma fila de tamanho fixo… em fim, a forma que você controla o cache, após a inclusão acima da capacidade tente fazer:

try { Thread.currentThread().sleep(5); } catch (InterruptedException ex) { Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); } System.gc(); try { Thread.currentThread().sleep(10); } catch (InterruptedException ex) { Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); }

Você estará aumentando a chance do resultado ser coletado pelo gc… só não irá funcionar se existir algum outro objeto fazendo referencia ao resultado que deveria ser eliminado da memória após ser removido do cache.

boa sorte

http://www.guj.com.br/posts/list/62245.java

Esse tópico explica o que é o problema e como resolve-lo: http://www.guj.com.br/posts/list/92491.java

Ressucitando o tópico.

Valeu pela ajuda de todos (acabei esquecendo desse tópico, porque devo ter clicado em parar de receber mensagens desse tópico…)

O permspace eu não estou mais tendo problemas, mandei ele alocar 700m de Permspace e não tive mais problema com isso.

Agora, o problema que estou tendo, é com o heap. Fiz o dump da aplicação quando ela alcança 900M de heap (sendo que ela assim que ligada, ocupa 130, mesmo com os testes de stress com o jmeter não passa disso). Pude perceber o seguinte, os objetos de sessão (logadas) não estão sendo recolhidos pelo GC (talvez a sessão não termine).

Fiz um teste, colocando no web.xml, para a sessão terminar depois de 1 minuto (nesse caso não preciso de sessão). E para as sessões logadas, no login, eu coloquei para 7200 minutos.

Revisei o código, e ao final de cada operação estou atribuíndo null as propriedades (que são objetos) que o meu bean de sessão (User) usa nessa operação.

Alguém tem ideia de mais algum cuidado especial que eu tenha que tomar nesse caso?

Cuidado com variáveis estáticas. O profiler do netbeans (e acho que o Visual VM também), tem uma opção para você rastrear quem é o root element de uma determinada instância. Se sua memória estiver lotada, pegue por amostragem algumas instâncias que tem cara de leak, e procure os root elements dela. Provavelmente será algum tipo de variável static, que em algum momento estará ligada a uma lista ou coisa do tipo, que mantém o resto do mundo vivo.

Variáveis estáticas só são coletadas quando são explicitamente setadas para null. Elas tem escopo global, então, muito cuidado com elas.

cara, verifiquei, era exatamente isso, algumas referências a algumas lists statics com elementos não statics. Um pequeno grande detalhe que tinha deixado passar!

Valeu, brigadão.

Quanto mais você usar profilers ou trabalhar com multiplas threads, mais vai estar convencido de que a palavra “static” devia ser banida da linguagem (ou se limitar apenas à constantes).

como assim? static não deveria tornar algumas propriedades da classe toda, ao invés de ser somente do objeto?

Sim. Mas tem várias desvantagens. Uma, que você mesmo observou, é que variáveis static nunca saem de escopo e, portanto, precisam de cuidados especiais na hora de serem zeradas.

Outra, é que a mesma static acaba compartilhada entre várias threads. É impossível fazer cópias por thread, o que complica muito as estratégias de paralelismo.

Depois, métodos estáticos não fazem polimorfismo, já que são da classe. Nem tem locks locais. Geralmente podem ser substituídos tranquilamente por classes e métodos não estáticos, que fazem o mesmo papel num contexto local.

É claro que existem exceções. Mas a medida que você usar mais profilers e threads, vai ver que elas são mais raras do que normalmente o pessoal implementa nos códigos por aí.

é, pensando por esse lado, realmente deve-se tomar muito cuidado.

É que normalmente, em aplicações web, eu costumo usar variáveis static para compartilhar algum valor entre todas as threads. Mas realmente, isso requer muito cuidado. (como acabei de deixar passar, heheheh)

Agora, se vai trabalhar com uma variável static, para que fazer uma cópia para cada thread? Tecnicamente ela seria para evitar que se criem muitas instâncias desse mesmo objeto.(pelo menos é assim que uso…) Ou para algum método que você precise de uma classe específica,mas não precisa instanciar a classe para isso (raramente crio algo assim)

Agora, aproveitando um pouco, conhece alguma forma (ou mesmo se existe), de eu verificar se ao instanciar alguma classe (através de um determinado ID único, por exemplo), eu verifique se já existe uma instància com o mesmo ID? Se possível, para não ter que mudar muito o código, queria fazer isso dentro do constructor dessa classe, ao invés de criar um método static que me faça esse trabalho.

[quote=evefuji]É que normalmente, em aplicações web, eu costumo usar variáveis static para compartilhar algum valor entre todas as threads. Mas realmente, isso requer muito cuidado. (como acabei de deixar passar, heheheh)

Agora, se vai trabalhar com uma variável static, para que fazer uma cópia para cada thread? Tecnicamente ela seria para evitar que se criem muitas instâncias desse mesmo objeto.(pelo menos é assim que uso…) Ou para algum método que você precise de uma classe específica,mas não precisa instanciar a classe para isso (raramente crio algo assim)
[/quote]

Se esse valor vai mudar, então, as threads terão que sincroniza-lo. E isso requer locks, que as enfileram.

Se o valor muda só no contexto da thread, então é melhor manter a cópia. Nesse caso, cada thread trabalhar com seu valor, independente e sem sincronização, e você obtém o máximo de paralelismo.

Copiar dados nem sempre é uma má alternativa, principalmente quando você lida com mais de uma thread.

Agora. Mesmo no caso de compartilhar valores entre threads, nada impede de você cria-los como não static e compartilha-los através de passagem de parâmetro.
É mais trabalhoso, mas mais seguro. :slight_smile:

O ideal nesse caso é usar alguma classe de cache. E, realmente, é um dos casos onde você acaba tendo algo mais estático. Só que, no caso, busque uma API que permita definir o tempo máximo de cache, para evitar um objeto que fique eternamente alocado por lá, e até para evitar que você use algo muito velho.