OutOfMemoryError usando ArrayList()

Pessoal, tenho um aplicativo que trabalha com listas, só que são muitos registros, algo em torno de 180 mil para mais em cada lista… Ja coloquei os parâmetros para aumentar a memória da JVM

-Xms128m -Xmx256m -XX:PermSize=128m -XX:MaxPermSize=256m

E ainda assim não resolveu meu problema…
Existe alguma outra forma de trabalhar com isso ??

Ora, se você tem uma lista de 180 mil objetos, então vai ocupar espaço mesmo. Tente um valor maior para -Xmx (no máximo 1.3G para 32 bits, e indefinido se você estiver usando uma JVM de 64 bits em um sistema operacional de 64 bits.)

Pois é, existe alguma outra estratégia para se trabalhar com um volume de dados como esse ??

Dependendo do que você quer fazer, você não precisa carregar TUDO em memória. Explique o que você tem de fazer (normalmente, nesses casos, há sempre alguma forma de fazer que não envolva tanta memória assim.)

[quote=thingol]Dependendo do que você quer fazer, você não precisa carregar TUDO em memória. Explique o que você tem de fazer (normalmente, nesses casos, há sempre alguma forma de fazer que não envolva tanta memória assim.)
[/quote]

Eu leio os dados de um arquivo texto e vou carregando em listas, para inserir no banco de uma só vez por batch usando Hibernate…
Os dados vem em um protocolo que eu desmonto e separo em listas…
Nesse caso eh um arquivo texto com 8 megas aproximadamente…

[quote=Guitar_Men][quote=thingol]Dependendo do que você quer fazer, você não precisa carregar TUDO em memória. Explique o que você tem de fazer (normalmente, nesses casos, há sempre alguma forma de fazer que não envolva tanta memória assim.)
[/quote]

Eu leio os dados de um arquivo texto e vou carregando em listas, para inserir no banco de uma só vez por batch usando Hibernate…
Os dados vem em um protocolo que eu desmonto e separo em listas…
Nesse caso eh um arquivo texto com 8 megas aproximadamente…[/quote]

Hum… Normalmente quando você precisa inserir uma grande quantidade de dados em um banco de dados, você cria um arquivo texto em um determinado formato (que depende do seu banco, é claro) e chama uma ferramenta do próprio banco que faz essa inserção monstro (normalmente são ferramentas de importação de dados que são características de cada banco); não se costuma usar o Hibernate, porque nesse caso você tem de criar toneladas de objetos para passar para o Hibernate.

Se a inserção for MONSTRO mesmo, o caminho é o sugerido pelo Thiago.(já utilizei o recurso do MySQL e digo que é FANTASTICO)

Algo que utilizo no dia a dia (mas não encontrei comprovação na documentação Java) é utilizar LinkedList ao invés de ArrayList. (se este for o seu caso)

O ArrayList (a não ser que eu esteja enganado) funciona como um vetor, ou seja, caso o tamanho máximo de armazenamento seja alcançado, o vetor precisa de um espaço de memória maior e contínuo para crescer armazenamento.
Se tal espaço não está disponível, “OutOfMemoryError”!!!

Já a LinkedList (por padrão da orientação a objetos) não possui essa limitação, fazendo assim melhor uso da memória disponível.

Tenta aê.

Obs: mas a criação do arquivo é a melhor solução.

Não posso usar algum recurso do banco para fazer pq não é simplesmente inserir no banco tem uma série de validações que precisam ser feitas via software, o próprio desemcapsulamento do protocolo…
O desempenho da LinkedList realmente é maior que do arraylist ??

[quote=Guitar_Men]Não posso usar algum recurso do banco para fazer q não simplesmente inserir no banco tem uma série de validações que precisam ser feitas via software, o próprio desemcapsulamento do protocolo…
O desempenho da LinkedList realmente é maior que do arraylist ??[/quote]

Não estou falando para você não fazer as validações. Só estou pedindo para, à medida que você for processando e validando os dados, ir gravando o que você já fez em um arquivo. De qualquer maneira, um arquivo de 8 MB é relativamente pequeno; acho que o gasto excessivo de memória é com o fato de usar o Hibernate* (porque aí você vai ter de usar uma montanha de objetos) em vez de criar um arquivo para chamar a ferramenta do banco de dados (procure por algo parecido com “import”, “imp” ou “bulk insert” na documentação do seu banco).

  • Eu não sou contra usar o Hibernate - muito pelo contrário, vivo recomendando o seu uso - mas acho que ele não serve para esse tipo de coisas (bulk insert).

Estou chegando a essa conclusão também, o hibernate eh muito bom pra trabalhar com sistemas “simples” sem milhões de inserções por operação.
Como modelei meu sistema usando DAO, vou partir para JDBC puro, acho que será mais fácil…
De qualquer forma muito obrigado pela ajuda pessoal…

Mesmo JDBC não é adequado para inserir muitos dados (ou seja, fazer uma “importação de dados”) em um banco de dados.
O correto é sempre usar BULK INSERT.

Eu utilizo o JDBC puro. Vou inserindo linha a linha, pois por incrível que pareça, utilizando o processo em batch, mesmo com algumas poucas linhas (50, 100 inserts) dava estouro de memória. Agora vai do tempo que tu necessida de importação desses arquivos no banco. Se precisar ser alguma coisa muito rápida, faça um job chamando um comando do proprio banco para a importação, como thingol falou, pois o processamento de inserção de milhares de linhas é muito demorado.

EDIT: Tem um artigo em uma revista mundo java (não me lembro a edição) que trata do assunto de inserção de milhares de registros com Hibernate…

Hummm… Então eu dei uma otimizada agora, após alguns registros processados na lista, eu insiro eles na base. Resultado, não tenho mais estouro de memória e obtive um desempenho satisfatório.
Não posso fazer um job do banco por que isso eh feito sobre demanda, tenho um aplicativo que manda os arquivos por ftp e chama a requisição de processamento na servlet. Esta servlet faz o processamento e retorna alguns parâmetros para o aplicativo. Acho que ja consegui otimizar bastante e agradeço a ajuda de todos…