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 = "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";
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 <= 18; i++) {
texto.append(rs.getString(i)).append(" ");
}
texto.append("\r\n");
cont = cont +1;
System.out.println(cont);
}
} catch (SQLException ex) {
ex.printStackTrace();
}
FileWriter pac = null;
try {
pac = new FileWriter(new File("C:\\\\pacientes_200" + ano + ".xls"));
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 <= 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]
Só um detalhe… esse seu código está muito bagunçado.
- No lugar do StringBuilder, por que você não cria um PrintWriter e já escreve diretamente no arquivo?
- 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;
- 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.
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.