Dedicar % da CPU para JVM

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?

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

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

Eis o meu codigo:

[code]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();
}

}[/code]

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:

[code]
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();
}

}[/code]

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;

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.

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.

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

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?

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 ?

Antes do while faça o

texto = new  StringBuilder();  

E depois de fechar o arquivo faça

texto = null;

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.

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

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.