[RESOLVIDO] - Estouro de Pilha - java.lang.StackOverflowError

Boa tarde pessoal, bom estou com esse problema descrito no cabeçalho do tópico não consigo resolver.

o Erro é esse:

Exception in thread “main” java.lang.StackOverflowError
at java.lang.Character.toUpperCase(Character.java:4278)
at java.lang.String.regionMatches(String.java:1383)
at java.lang.String.equalsIgnoreCase(String.java:1119)
at sun.net.spi.DefaultProxySelector$3.run(DefaultProxySelector.java:212)
at java.security.AccessController.doPrivileged(Native Method)
at sun.net.spi.DefaultProxySelector.select(DefaultProxySelector.java:201)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:358)
at java.net.Socket.connect(Socket.java:529)
at java.net.Socket.connect(Socket.java:478)
at java.net.Socket.(Socket.java:375)
at java.net.Socket.(Socket.java:189)
at org.postgresql.core.PGStream.(PGStream.java:62)
at org.postgresql.core.v3.ConnectionFactoryImpl.openConnectionImpl(ConnectionFactoryImpl.java:76)
at org.postgresql.core.ConnectionFactory.openConnection(ConnectionFactory.java:66)
at org.postgresql.jdbc2.AbstractJdbc2Connection.(AbstractJdbc2Connection.java:125)
at org.postgresql.jdbc3.AbstractJdbc3Connection.(AbstractJdbc3Connection.java:30)
at org.postgresql.jdbc3.Jdbc3Connection.(Jdbc3Connection.java:24)
at org.postgresql.Driver.makeConnection(Driver.java:393)
at org.postgresql.Driver.connect(Driver.java:267)
at java.sql.DriverManager.getConnection(DriverManager.java:582)
at java.sql.DriverManager.getConnection(DriverManager.java:185)
at caixa.sp1.job.util.ConexaoPostgreSQL.(ConexaoPostgreSQL.java:36)

Não é tudo mas até onde interessa, o resto é só repeteco.

O que eu faço para calsar esse erro.

----------------------- Leitor do Arquivo -----------------------

public void entidadeIni(Scanner scan, File arquivo) {
        if (arquivo.exists()) {
            try {

                //Scanea o arquivo se for nulo
                if (scan == null) {
                    scan = new Scanner(arquivo);
                }

                //Iniciar leitura do arquivo
                while (scan.hasNextLine()) {
                    Util.numLinhaFimArquivo++;
                    String textoLinha = scan.nextLine();

                    //Comparando valores da entidade
                    if (Util.numLinhaFimArquivo > logCarga.getNumeroLinhaLida()) {
                        for (int i = 0; i < dados.length; i++) {
                            if (textoLinha.contains(dados[i])) {
                                nagiosLogControle.dados(textoLinha, dados[i], scan, arquivo);
                            }
                        }
                    }
                }
            } catch (FileNotFoundException ex) {
                System.out.println("ERRO03 - Arquivo inexistente no caminho especificado: " + ex);
            }
        }
    }

----------------------- Grava -----------------------

public void dados(String textoLinha, String nomeEvento, Scanner scan, File arquivo) {
        linhaDados = textoLinha.replaceAll("\\[|\\]|" + nomeEvento + "", "").replaceFirst(":", "|").replaceAll(";", "|").replaceFirst(" ", "").replaceFirst(" ", "");
        nagiosLog.setNomeEvento(nomeEvento);
        nagiosLog.setTuplaEvento(linhaDados);
        inserir(scan, arquivo);
    }

public void inserir(Scanner scan, File arquivo) {
        //Gravando linha de dados no banco
        dao = new NagiosLogDAO();
        dao.inserir(nagiosLog);

        //Términando a gravação continua a leitura
        nagiosLogService = new NagiosLogService();
        nagiosLogService.entidadeIni(scan, arquivo);
    }

Bom pessoal o básico é isso. O problema é que se o arquivo tem até umas 1000 linhas ele nãdá erro nenhum, funciona perfeitamente, acima disso dá o erro de estouro de pilha.

Observando essa linha ------------- at caixa.sp1.job.util.ConexaoPostgreSQL.(ConexaoPostgreSQL.java:36) -------------

Pode-se observar que não consegue mais abrir conexão, para inseriri por isso causa esse estouro, o problema é que não tenho nem como começar a procurar para resolver.

--------- Classe Conexão


    private String driver = "org.postgresql.Driver";
    private String url = "jdbc:postgresql://ip_servidor:5432/rdacesso001";//Desenvolvimento PG-8.4.11
    private String user = "";
    private String password = "";
    private Connection conn;

  
    public ConexaoPostgreSQL() {
        try {
            Class.forName(driver);
            try {
                conn = DriverManager.getConnection(url, user, password);
            } catch (SQLException excessao) {
                System.out.println("Erro na conexão com o banco: " + excessao);
            }
        } catch (ClassNotFoundException excessao) {
            System.out.println("Erro na conexão com do driver com o banco: " + excessao);
        }
    }


    public Connection abreConn() {
        return conn;
    }


    public void fechaConn() {
        try {
            conn.close();
        } catch (Exception excessao) {
            System.out.println("Erro ao encerrar a conexão com o banco: " + excessao);
        }
    }

--------------------------- Classe Inserir ----------------------------------

protected PreparedStatement pstmt;
    protected ResultSet rs;
    protected ConexaoPostgreSQL conexaoPostgreSQL;
    private static final String INSERIR = "INSERT INTO tb002_nagios_log("
            + "no_evento, tupla_evento"
            + ") "
            + "VALUES(?, ?);";

public void inserir(NagiosLog nagiosLog) {
        conexaoPostgreSQL = new ConexaoPostgreSQL();
        try {
            conexaoPostgreSQL.abreConn().createStatement().executeUpdate("VACUUM tb002_nagios_log");//Uma parada que implemento pra evitar o erro mas não funcionou
            pstmt = conexaoPostgreSQL.abreConn().prepareStatement(INSERIR);

            pstmt.setString(1, nagiosLog.getNomeEvento());
            pstmt.setString(2, nagiosLog.getTuplaEvento());

            pstmt.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            DAOUtil.fechar(conexaoPostgreSQL, pstmt, rs);
        }
    }

AJUDEMMMMMMMMMMMMMMMMMMMMMMMMMM.

O Caused by é importante coloca a stackTrace completa ai.

Opa i ai Samuel blz?

Cara todo o stackTrace está ai, o resto somente repete. Cara esse problema já é velho. Mas até hoje ninguém me ajudou.

Tem uma coisa que ainda não tentei, mas também não tenho idéia de como fazer.

O insert do banco deveria ficar assim

insert into table(col1, col2, col3) values(?,?,?), (?,?,?), (?,?,?), (?,?,?), …(?,?,?);
Alguém tem algum exemplo ou idéia de como proceder nesse caso?

Acho que seu problema de memória não é em relação ao arquivo mas por conta do seu for() dentro do while(). No for() você chama o método dados(), que chama o método inserir(), que chama o método entidadeIni(). Você está criando uma grande pilha na memória.

Mude essa lógica para evitar essa pilha. Ao invés de chamar um método dentro de outro, trabalhe com retorno.

Veja que no seu método dados() você usa os parametros scan e arquivo apenas para adicionar no método inserir(), em nenhum momento você trabalha com eles dentro do método. Então, não precisa chamar inserir() dentro de dados(), faça a chamada após o término da execução de dados().

E a mesma coisa acontece dentro do método inserir. Scan e arquivo não são usados pelo método a não ser para a chamada a entidadeIni(). Retire também essa parte de dentro do método.

[quote=romarcio]Acho que seu problema de memória não é em relação ao arquivo mas por conta do seu for() dentro do while(). No for() você chama o método dados(), que chama o método inserir(), que chama o método entidadeIni(). Você está criando uma grande pilha na memória.

Mude essa lógica para evitar essa pilha. Ao invés de chamar um método dentro de outro, trabalhe com retorno.

Veja que no seu método dados() você usa os parametros scan e arquivo apenas para adicionar no método inserir(), em nenhum momento você trabalha com eles dentro do método. Então, não precisa chamar inserir() dentro de dados(), faça a chamada após o término da execução de dados().

E a mesma coisa acontece dentro do método inserir. Scan e arquivo não são usados pelo método a não ser para a chamada a entidadeIni(). Retire também essa parte de dentro do método.[/quote]

Então romarcio, o “dados” não se trata de um método e sim de uma arranjo de String:

private String[] dados = {“CURRENT HOST STATE”, “CURRENT SERVICE STATE”, “SERVICE ALERT”, “HOST ALERT”};

onde ele compara no arquivo esses valores para importar para o banco, pra não importar lixo.

Até umas 1400 linhas ele importa, depois dá o erro e encerra a importação.

Atenção que já deram a dica aí ! Fique de olho nas chamadas recursivas

Só para confirmar: o método entidadeIni chamado no final do método dados() é o mesmo que está listado no começo?

Fiz a mesma coisa que você nesse programa, se quiser faça o teste:
Execute o programa abaixo, vá aumentando o NUM_REGISTROS até dar StackOverflow (aqui foi em 10000).
Depois tente observar o que ele tem de estranho

[code]public class Recursiv {

private static final int NUM_REGISTROS = 10000;

static int ultimoNumeroLido = 0;

public static void main(String[] args) {
	fazUmaCoisa();
	System.out.println("ok");
}

private static void fazUmaCoisa() {
	for (int i = 1; i < NUM_REGISTROS; i++) {
		if (i > ultimoNumeroLido) {
			fazOutraCoisa();
		}
	}
}

private static void fazOutraCoisa() {
	fazATerceiraCoisa();
	ultimoNumeroLido++;
	fazUmaCoisa();
}

private static void fazATerceiraCoisa() {
	
}

}
[/code]

Então essa trecho:

if (textoLinha.contains(dados[i])) { nagiosLogControle.dados(textoLinha, dados[i], scan, arquivo); }
Não chama esse método?

public void dados(String textoLinha, String nomeEvento, Scanner scan, File arquivo) { linhaDados = textoLinha.replaceAll("\\[|\\]|" + nomeEvento + "", "").replaceFirst(":", "|").replaceAll(";", "|").replaceFirst(" ", "").replaceFirst(" ", ""); nagiosLog.setNomeEvento(nomeEvento); nagiosLog.setTuplaEvento(linhaDados); inserir(scan, arquivo); }

Galera valeu pelo esforço em me ajudar mas já cheguei a uma solução. Como trabalho com JDBC o jeito foi inserir dados no banco em lotes.

Com base nisso estudei um pouco sobre batch e fiz a implementação que resolveu bem o problema. Agora ta tudo certo. Ficou assim:

Modelo----------------------------

public void entidadeIni(Scanner scan, File arquivo) {
        if (arquivo.exists()) {
            try {

                //Scanea o arquivo se for nulo
                if (scan == null) {
                    scan = new Scanner(arquivo);
                }

                //Iniciar leitura do arquivo
                while (scan.hasNextLine()) {
                    Util.numLinhaFimArquivo++;
                    String textoLinha = scan.nextLine();

                    //Comparando valores da entidade
                    if (Util.numLinhaFimArquivo > logCarga.getNumeroLinhaLida()) {
                        for (int i = 0; i < dados.length; i++) {
                            if (textoLinha.contains(dados[i])) {
                                String linhaDados = textoLinha.replaceAll("\\[|\\]|" + dados[i] + "", "").replaceFirst(":", "|").replaceAll(";", "|").replaceFirst(" ", "").replaceFirst(" ", "");

                                NagiosLog nagiosLog = new NagiosLog();
                                nagiosLog.setNomeEvento(dados[i]);
                                nagiosLog.setTuplaEvento(linhaDados);

                                dadosInserir.add(nagiosLog);
                            }
                        }
                    }
                }
            } catch (FileNotFoundException ex) {
                System.out.println("ERRO03 - Arquivo inexistente no caminho especificado: " + ex);
            }
            nagiosLogControle.inserirBatch(dadosInserir);
        }
    }

Controle----------------------------

public void inserirBatch(List dadosInserir) {
        dao = new NagiosLogDAO();
        dao.inserirBatch(dadosInserir);
    }

DAO----------------------------

public void inserirBatch(List dadosInserir) {
        conexaoPostgreSQL = new ConexaoPostgreSQL();
        conn = conexaoPostgreSQL.abreConn();
        int cont = 0;
        try {
            conn.setAutoCommit(false);
            pstmt = conn.prepareStatement(INSERIR);

            for (Object object : dadosInserir) {
                cont++;
                NagiosLog nagiosLog = (NagiosLog) object;
                Object[] array = new Object[2];
                array[0] = nagiosLog.getNomeEvento();
                array[1] = nagiosLog.getTuplaEvento();

                pstmt.setString(1, nagiosLog.getNomeEvento());
                pstmt.setString(2, nagiosLog.getTuplaEvento());
                pstmt.addBatch();

                if ((++cont % 1000) == 0) {
                    pstmt.executeBatch();
                    cont = 0;
                }
            }

            pstmt.executeBatch();
            conn.commit();
        } catch (SQLException ex) {
            ex.printStackTrace();
        } finally {
            DAOUtil.fechar(conexaoPostgreSQL, pstmt, rs);
        }
    }

Bom galera fica ai a dica pra quem precisar fique a vontade. Programando e aprendendo.

Salve salve nobres colegas do GUJ, passando mesmo só pra fazer algumas recomendações sobre a solução acima.

Bom pessoal, no exemplo utilizo a classe Scanner para fazer a leitura das linhas do arquivo.

A classe Scanner roda bem até uma determinada quantidade de linhas e armazenamento de cash da virtualização do JAVA.

Por esse motivo resolvi mudar o Scanner para o BufferReader, que é bem mais robusto e veloz.

Sugiro a vocês fazerem o mesmo.

Abraço.