Dedicar % da CPU para JVM

12 respostas
W

Boa tarde, estou com um programa que está fazendo o seguinte: Ele lê uma tabela em uma base de dados informix, é uma tabela bem extensa, mais ou menos 160.000 registros, e eu estou exportando esses dados da seguinte maneira: Faço uma conexão com o banco por anos e dai vou salvando cada linha de resultado que o ResultSet me retorna em uma unica String, para só depois eu gravar essa string em um arquivo de texto. Dai eu mandei iterar os anos, 2001,2002,2003 … sendo cada ano um arquivo de texto novo. Mas quando eu executo o programa ele me ocupa 100% do processamento quando está lendo do banco e armazenando na String. Não sei se minha logica está tão errada assim, mas se não estiver, tem como eu limitar a quantidade de processamento que meu programa utilizara da cpu?

12 Respostas

V

Você está usando StringBuilder para montar essa String? Pode postar o código?

Talvez seja uma boa colocar um Thread.yield() no seu loop.

W

Eis o meu codigo:

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Main {

    int ano;
    ResultSet rs = null;
    String linha = "";
    String cabe = "cod_con	cod_prt	nome_pac	nome_mae	nome_pai	nascimento	sexo	identidade	cpf	fone_res	end_res	bai_res	cid_res	est_res	cep_res	nacionalidade	uf_naturalidade	orgao_emissor_id" + "\r\n";
    String texto = "";
    Dao d = new Dao();

    public void init(String inicio, String fim) {
        d.concectaWpd ();
        try {
            d.pesquisaPacientes(inicio, fim);
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
        rs = d.getRs();
        int cont = 0;
        try {
            while (rs.next()) {
                linha = rs.getString(1) + "	" + rs.getString(2) + "	" + rs.getString(3) + "	" + rs.getString(4) +
                        "	" + rs.getString(5) + "	" + rs.getString(6) + "	" + rs.getString(7) + "	" + rs.getString(8) + "	" + rs.getString(9) + "	" + rs.getString(10) + "	" + rs.getString(11) + "	" + rs.getString(12) + "	" + rs.getString(13) + "	" + rs.getString(14) + "	" + rs.getString(15) + "	" + rs.getString(16) + "	" + rs.getString(17) + "	" + rs.getString(18) + "\r\n";
                texto = texto + linha;
                cont = cont +1;
                System.out.println(cont);
            }
            texto = cabe + texto;
        } catch (SQLException ex) {
            ex.printStackTrace();
        } finally {
            cabe = "";
        }
        FileWriter pac;
        try {
            pac = new FileWriter(new File("C:\\\\pacientes_200" + ano + ".xls"));
            pac.write(texto);
            pac.close();
        } catch (IOException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void executa() {
        ano = 1;
        while (ano <= 10) {
            if (ano <= 9) {
                init("200" + ano + "-01-01", "200" + ano + "-12-31");
            } else {
                init("20" + ano + "-01-01", "20" + ano + "-12-31");
            }
            ano++;
        }
    }

    public static void main(String[] args) {
        new Main().executa();
    }
}
V

Jamais concatene strings num loop usando a classe String. No lugar, use o StringBuilder.

Caso contrário, seu código ficará extremamente lento. O código corrigido fica assim:
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Main {

    int ano;
    ResultSet rs = null;
    
    String cabe = &quot;cod_con	cod_prt	nome_pac	nome_mae	nome_pai	nascimento	sexo	identidade	cpf	fone_res	end_res	bai_res	cid_res	est_res	cep_res	nacionalidade	uf_naturalidade	orgao_emissor_id&quot; + &quot;\r\n&quot;;
    StringBuilder texto = new StringBuilder();
	
    Dao d = new Dao();

    public void init(String inicio, String fim) {
        d.concectaWpd ();
        try {
            d.pesquisaPacientes(inicio, fim);
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
        rs = d.getRs();
        int cont = 0;
        try {
            while (rs.next()) {
                for (int i = 0; i &lt;= 18; i++) {
                    texto.append(rs.getString(i)).append(&quot; &quot;);
                }
				
                texto.append(&quot;\r\n&quot;);
				
                cont = cont +1;
                System.out.println(cont);
            }            
        } catch (SQLException ex) {
            ex.printStackTrace();
        }
        FileWriter pac = null;
        try {
            pac = new FileWriter(new File(&quot;C:\\\\pacientes_200&quot; + ano + &quot;.xls&quot;));
            pac.write(texto.toString());            
        } catch (IOException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
        finally {
             if (pac != null) pac.close();
        }
    }

    public void executa() {
        ano = 7;
        while (ano &lt;= 10) {
            if (ano &lt;= 9) {
                init(&quot;200&quot; + ano + &quot;-01-01&quot;, &quot;200&quot; + ano + &quot;-12-31&quot;);
            } else {
                init(&quot;20&quot; + ano + &quot;-01-01&quot;, &quot;20&quot; + ano + &quot;-12-31&quot;);
            }
            ano++;
        }
    }

    public static void main(String[] args) {
        new Main().executa();
    }
}

Só um detalhe... esse seu código está muito bagunçado.
1. No lugar do StringBuilder, por que você não cria um PrintWriter e já escreve diretamente no arquivo?
2. Certifique-se de estar fechado o Statement e a Connection ao final do processo. Caso contrário, pode haver um memory leak grave na sua aplicação;
3. Geralmente, é uma boa prática usar o método getString() passando o nome da coluna, não o índice;

J

Rapaz, crie uma Thread para fazer esse serviço e sete-a para ter prioridade baixa no sistema. Assim o sistema operacional vai entender para não escalonar esse processo como crítico.

W

Ok senhores, muito obrigado pelas correções, se puderem me ajudar em como escrever direto no arquivo com PrintWriter e como definir uma thread para ter baixa prioridade no sistema.

J

http://www.java2s.com/Tutorial/Java/0160__Thread/ChangeThreadPriority.htm

W

Obrigado Julho, vou dar uma olhada no link. Vini, implementei o codigo como vc mostrou mas tive uma exeption na linha:

pac.write(texto.toString());

A exception foi:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOfRange(Arrays.java:3209) at java.lang.String.<init>(String.java:215) at java.lang.StringBuilder.toString(StringBuilder.java:430) at pacientes.Main.init(Main.java:47) at pacientes.Main.executa(Main.java:65) at pacientes.Main.main(Main.java:74) Java Result: 1

Ele chegou a criar mais um ano ai quando começou a processar o proximo de esse erro.

O que pode ter ocorrido?

W

Percebi que os arquivos tem em torno de 6 a 7 megas, mas o ano de 2009 é um pouco maior. Será falta de memória esse java.lang.OutOfMemoryError: Java heap space ?

V

Antes do while faça o

texto = new  StringBuilder();

E depois de fechar o arquivo faça

texto = null;
V

Sim, é falta de memória. Se seu arquivo é muito grande, talvez seja necessário iniciar a vm com o comando:
java seuPrograma -XMX500M

É que por padrão a VM ocupa no máximo 64MB de memória. Se a a aplicação tentar usar mais que isso, ela acusará falta de memória.

W

Agora deu certo, mais uma vez muito obrigado pela ajuda.

J

o viny resolveu, blz…
Só fique atento aos mais diversos hardwares. É interessante você criar um algoritmo que otimize essa tarefa da melhor maneira possível, tanto em consumo de memória, quanto cpu.

Criado 20 de maio de 2010
Ultima resposta 20 de mai. de 2010
Respostas 12
Participantes 3