OutOfMemoryError: Java heap space

7 respostas
H

Olá pessoal, estou tentando desenvolver uma aplicação para ler um CSV, separar alguns campos, montar um objeto, para que futuramente possa manipular esse objeto como bem entender ...

Porém esse CSV é mtoooooo grande, cerca de 40 milhões de registros !
Montei uma aplicaçãozinha em cima de uma amostra de teste, deu certo, porém quando vou colocar pra rodar na amostra verdadeira recebo esse seguinte erro ?OutOfMemoryError: Java heap space? =/

Vou postar a aplicação aqui, se alguém puder me ajudar a dar uma otimizada no código ficarei mto grato :D

import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;

import model.Consulta;

public class ManipulaArquivo {

	private String caminho = "PABLOCALTESTE.txt";

	public void lerArquivo() {
		try {
			BufferedReader leitor = AbrirArquivo();
			String linha = null;
			ArrayList<Consulta> listObjConsulta = new ArrayList<Consulta>();

			while ((linha = leitor.readLine()) != null) {
				Consulta objConsulta = new Consulta();

				int posIni = 0; 
				int posFim = 0;

				posFim = linha.indexOf(";", posIni);
				objConsulta.setBilhetador(linha.substring(posIni, posFim));

				posIni = linha.indexOf(";", posFim) + 1; 
				posFim = linha.indexOf(";", posIni);
				objConsulta.setOrigem(linha.substring(posIni, posFim));
 
				posIni = linha.indexOf(";", posFim) + 1; // solução encontrada para pular uma coluna no CSV
				posIni = linha.indexOf(";", posIni) + 1;
				posFim = linha.indexOf(";", posIni);
				objConsulta.setDestino(linha.substring(posIni, posFim));

				posIni = linha.indexOf(";", posFim) + 1; // solução encontrada para pular uma coluna no CSV
				posIni = linha.indexOf(";", posIni) + 1;
				posFim = linha.indexOf(";", posIni);
				objConsulta.setRotaEntrada(linha.substring(posIni, posFim));

				posIni = linha.indexOf(";", posFim) + 1; 
				posFim = linha.indexOf(";", posIni);
				objConsulta.setRotaSaida(linha.substring(posIni, posFim));

				posIni = linha.indexOf(";", posFim) + 1; 
				posFim = linha.indexOf(";", posIni);
				objConsulta.setFds(linha.substring(posIni, posFim));

				posIni = linha.indexOf(";", posFim) + 1; 
				posFim = linha.indexOf(";", posIni);
				objConsulta.setDataHora(linha.substring(posIni, posFim));

				posIni = linha.indexOf(";", posFim) + 1; 
				posFim = linha.indexOf(";", posIni);
				objConsulta.setTtc(linha.substring(posIni, posFim));
				listObjConsulta.add(objConsulta);
				
				
			}
			System.out.println(listObjConsulta.size());
		} catch (Exception e) {
			// TODO: handle exception
		}
	}

	private BufferedReader AbrirArquivo() {
		try {
			FileReader reader = new FileReader(caminho);
			BufferedReader leitor = new BufferedReader(reader, 1 * 512 * 512);
			return leitor;
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return null;
		}
	}

}

7 Respostas

ViniGodoy

É loucura tentar salvar todos os objetos num list. Jogue-os diretamente num banco de dados.
Depois, você terá que trabalhar com essa massa aos poucos, com paginação.

Rodrigo_Sasaki

Você precisa mesmo ter essa lista aí?

Se precisar uma coisa que pode ajudar (não resolver) é setar o tamanho inicial dela pra 40 milhões logo de início, assim ela não precisa ficar aumentando dinamicamente.

H

Ok, vou fazer isso então … Já desconfiava que essa parada de salvar em um arraylist não ia dar certo =/
mas em relação ao código está tudo OK ?:smiley:

Rodrigo_Sasaki

ViniGodoy:
É loucura tentar salvar todos os objetos num list. Jogue-os diretamente num banco de dados.
Depois, você terá que trabalhar com essa massa aos poucos, com paginação.

Não poderia ir tratando as massas aos poucos diretamente no CSV? sem jogar nada em um BD?

H

O problema de ir “fazendo aos poucos” é que preciso de TODOS os dados de uma vez, para que eu possa fazer algumas operações com eles =/

Bom, na verdade esse CSV que vem pra mim, existem muitos registros duplicados, porém é preciso que eu faça alguns procedimentos para saber se são duplicados ou não …
Então não sei se seria melhor eu inserir toda essa massa direto no BD para depois tirar a duplicidades ou tratar isso direto no Java, e mandar para o BD apenas os dados não duplicados …

ViniGodoy
hamisterbr:
Ok, vou fazer isso então ... Já desconfiava que essa parada de salvar em um arraylist não ia dar certo =/ mas em relação ao código está tudo OK ?:D

Aparentemente sim. Mas seria bem mais fácil usar o comando split. Ele já gera um array partido num separador, definido numa expressão regular:

String[] campos = linha.split(";");

Desde o Java 5 também tenho usado o Scanner para ler arquivos, ao invés do BufferedReader. A vantagem é só a sintaxe que é um pouco mais limpa.

Um outro problema é aquele seu método AbrirArquivo. O certo seria deixar tudo num try with resources, para garantir que o arquivo será fechado mesmo em caso de exceção. Também é um erro ignorar as exceções.

Veja:
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.ArrayList;

import model.Consulta;

public class ManipulaArquivo {
    private static final String CAMINHO = "PABLOCALTESTE.txt";

    public void lerArquivo() {
        try (Scanner in = new Scanner(CAMINHO)) {
            ArrayList<Consulta> listObjConsulta = new ArrayList<Consulta>();

            while (in.hasNextLines()) {
                String campos[] = in.nextLine().split(";"); 
                Consulta objConsulta = new Consulta();
                objConsulta.setBilhetador(campos[0]);
                objConsulta.setOrigem(campos[1]);
                objConsulta.setDestino(campos[3]);
                objConsulta.setRotaEntrada(campos[5]); //Pulando uma coluna
                objConsulta.setRotaSaida(campos[6]);
                objConsulta.setFds(campos[7]);
                objConsulta.setDataHora(campos[8]);
                objConsulta.setTtc(campos[9]);
                listObjConsulta.add(objConsulta);
        } catch (Exception e) {
            throw new RuntimeException("Não foi possível ler o arquivo!", e);
        }
    }
}
H

não sei se crio outro tópico para perguntar isso ou não, mas uma solução que achei para meu problema seria …
tratar esses arquivos por um exemplo de 1k em 1k ou 10k em 10k.
Toda vez que o csv ler 10k de linhas, eu parar a leitura e fazer os procedimentos, acabando os procedimentos retomo com a leitura …
alguém pode me dar umas dicas de como fazer isso de uma maneira mais “elegante” e produtiva ?

Criado 14 de novembro de 2012
Ultima resposta 16 de nov. de 2012
Respostas 7
Participantes 3