LIMPAR MEMÓRIA DE CLASSE INSTANCIADA
Boa Tarde!!
Estou com um problema...
Tenho um processamento que gera boleto de maneira massiva, porém o mesmo começa a ficar lento e quando vejo ele consumiu toda memória ram.
Ja tentei usar o GC e implementar a interface idisposable...
Mas nao deu certo...
Alguem pode me ajudar com exemplos do GC ou implementar idisposable.
Obrigado!
Estou com um problema...
Tenho um processamento que gera boleto de maneira massiva, porém o mesmo começa a ficar lento e quando vejo ele consumiu toda memória ram.
Ja tentei usar o GC e implementar a interface idisposable...
Mas nao deu certo...
Alguem pode me ajudar com exemplos do GC ou implementar idisposable.
Obrigado!
Não adianta implementar a interface, tem que fazer uso de blocos using.
Bom dia Kerplunk!
Percebi que este trecho do código que esta comendo minha memoria. quando comento ele, a memória estabiliza.
Tentei implementar o using mas nao consegui.. pode me ajudar?
byte mbytes = rv.localreport.render([Ô]pdf[Ô])
tentei assim
using(byte mbytes = rv.localreport.render([Ô]pdf[Ô]));
fs.write(mybytes,0,mybytes.length);
{
}
Ele nao aceita..
O comando acima renderiza um reportviewer para um PDF que posteriormente gravo um aquivo.
abrs.
Percebi que este trecho do código que esta comendo minha memoria. quando comento ele, a memória estabiliza.
Tentei implementar o using mas nao consegui.. pode me ajudar?
byte mbytes = rv.localreport.render([Ô]pdf[Ô])
tentei assim
using(byte mbytes = rv.localreport.render([Ô]pdf[Ô]));
fs.write(mybytes,0,mybytes.length);
{
}
Ele nao aceita..
O comando acima renderiza um reportviewer para um PDF que posteriormente gravo um aquivo.
abrs.
Muito provavelmente o Dispose não vai te ajudar em nada.
Dispose não serve para liberar memória, a chamada ao Dispose simplesmente informa ao objeto que ele não é mais necessário e que ele pode liberar os recursos não gerenciados dele, o que geralmente foi obtido por chamadas a bibliotecas externas que não são feitas em .Net, mas falando assim parece algo [Ô]mágico[Ô] e não é bem assim, ele só vai fazer isso se quem escreveu o código deste objeto fez com que ele funcionasse desta forma.
No geral você deve se preocupar em chamar Dispose, de preferência pelo uso do bloco using sempre que possÃvel, já implementar a interface IDisposable vai ser algo muito mais raro de se precisar e você precisa saber o que está fazendo ou a implementação dela vai ser sem utilidade alguma.
Pelo pouco do código que você postou, me parece que seu problema é que você gera grandes arrays de bytes, o que se for feito em um loop vai realmente ocupar uma grande quantidade de memória e provavelmente é ai o seu problema.
Uma coisa que talvez funcione é em vez de usar este método Render que é o mais simples, usar um dos que tem como parâmetro um callback para passar o Stream que vai ser usado.
Eu não testei, mas um exemplo básico usando Lambda para passar o callback seria
Porém isso só deve resolver seu problema se ele estava no fato de se criar vários arrays de bytes, se o problema for interno do ReportViewer pode ser mais difÃcil resolver.
Dispose não serve para liberar memória, a chamada ao Dispose simplesmente informa ao objeto que ele não é mais necessário e que ele pode liberar os recursos não gerenciados dele, o que geralmente foi obtido por chamadas a bibliotecas externas que não são feitas em .Net, mas falando assim parece algo [Ô]mágico[Ô] e não é bem assim, ele só vai fazer isso se quem escreveu o código deste objeto fez com que ele funcionasse desta forma.
No geral você deve se preocupar em chamar Dispose, de preferência pelo uso do bloco using sempre que possÃvel, já implementar a interface IDisposable vai ser algo muito mais raro de se precisar e você precisa saber o que está fazendo ou a implementação dela vai ser sem utilidade alguma.
Pelo pouco do código que você postou, me parece que seu problema é que você gera grandes arrays de bytes, o que se for feito em um loop vai realmente ocupar uma grande quantidade de memória e provavelmente é ai o seu problema.
Uma coisa que talvez funcione é em vez de usar este método Render que é o mais simples, usar um dos que tem como parâmetro um callback para passar o Stream que vai ser usado.
Eu não testei, mas um exemplo básico usando Lambda para passar o callback seria
Warning[] warnings;
using (var fs = new FileStream([Ô]caminho[Ô], FileMode.Create))
{
rv.LocalReport.Render([Ô]PDF[Ô], null, (n, ex, en, m, w) => fs, out warnings);
fs.Flush();
fs.Close();
}
Porém isso só deve resolver seu problema se ele estava no fato de se criar vários arrays de bytes, se o problema for interno do ReportViewer pode ser mais difÃcil resolver.
Bom dia Ocelot!
Obrigado pelo retorno,
Analisando mais o código o trecho que esta acabando com a memória é este rv.localreport.render([Ô]pdf[Ô])) independente de mandar em um array de bytes ou nao...
Na internet muita gente reclama e chama isso de memory leak... vou tentar com lambda para ver se ajuda.
Pode me explicar algumas coisas no seu código:
Warning[] warnings;
(n, ex, en, m, w) => fs, out warnings
Oque sao estas letras n, ex, en
Abraço!
Obrigado pelo retorno,
Analisando mais o código o trecho que esta acabando com a memória é este rv.localreport.render([Ô]pdf[Ô])) independente de mandar em um array de bytes ou nao...
Na internet muita gente reclama e chama isso de memory leak... vou tentar com lambda para ver se ajuda.
Pode me explicar algumas coisas no seu código:
Warning[] warnings;
(n, ex, en, m, w) => fs, out warnings
Oque sao estas letras n, ex, en
Abraço!
A função Render que usei ali é a seguinte
O terceiro parâmetro dela é uma delegate do tipo CreateStreamCallback, a assinatura desta delegate é
Só que usar delegates pode ser meio trabalhoso quando comparado com expressões Lambda, então para simplificar o uso deste delegate eu criei uma Lambda
Onde cada uma destas letras é equivalente a cada um dos parâmetros do CreateStreamCallback, como o nome dos parâmetros não é importante eu usei o mÃnimo de letras para deixar menor o código, já que não vamos usar nenhum destes parâmetros mesmo. Então
n = name
ex = extension
en = encoding
m = mimeType
w = willSeek
Eu poderia fazer exatamente a mesma coisa usando uma delegate anônima, ficaria assim
Até seria possivel simplificar um pouco mais assim
Mas mesmo assim acho que dá para perceber que usando Lambda fica muito mais compacto, e as 3 formas fazem praticamente a mesma coisa
Já o Warning[] warnings é que a função Render tem um parâmetro que precisa de uma variável deste tipo, o ReportViewer retorna nesta variável todos os avisos de problemas que tiveram durante o processamento do relatório, no caso só coloquei ela por ser obrigatório ter ela para poder chamar esta função, mesmo que você não pretenda usar estas informações.
public void Render (string format, string deviceInfo, CreateStreamCallback createStream, out Warning[] warnings)
O terceiro parâmetro dela é uma delegate do tipo CreateStreamCallback, a assinatura desta delegate é
public delegate Stream CreateStreamCallback (string name, string extension, Encoding encoding, string mimeType, bool willSeek)
Só que usar delegates pode ser meio trabalhoso quando comparado com expressões Lambda, então para simplificar o uso deste delegate eu criei uma Lambda
(n, ex, en, m, w) => fs
Onde cada uma destas letras é equivalente a cada um dos parâmetros do CreateStreamCallback, como o nome dos parâmetros não é importante eu usei o mÃnimo de letras para deixar menor o código, já que não vamos usar nenhum destes parâmetros mesmo. Então
n = name
ex = extension
en = encoding
m = mimeType
w = willSeek
Eu poderia fazer exatamente a mesma coisa usando uma delegate anônima, ficaria assim
Warning[] warnings;
using (var fs = new FileStream([Ô]caminho[Ô], FileMode.Create))
{
rv.LocalReport.Render([Ô]PDF[Ô], null, delegate(string name, string extension, Encoding encoding, string mimeType, bool willSeek)
{
return fs;
}, out warnings);
fs.Flush();
fs.Close();
}
Até seria possivel simplificar um pouco mais assim
Warning[] warnings;
using (var fs = new FileStream([Ô]caminho[Ô], FileMode.Create))
{
rv.LocalReport.Render([Ô]PDF[Ô], null, delegate(string n, string ex, Encoding en, string m, bool w){return fs;}, out warnings);
fs.Flush();
fs.Close();
}
Mas mesmo assim acho que dá para perceber que usando Lambda fica muito mais compacto, e as 3 formas fazem praticamente a mesma coisa
Já o Warning[] warnings é que a função Render tem um parâmetro que precisa de uma variável deste tipo, o ReportViewer retorna nesta variável todos os avisos de problemas que tiveram durante o processamento do relatório, no caso só coloquei ela por ser obrigatório ter ela para poder chamar esta função, mesmo que você não pretenda usar estas informações.
Nossa, que aula. Muito obrigado Ocelot
vc sugere alguma coisa com relacao ao rv.LocalReport.Render(
Nao adianta eu dar dispose... cada vez que passo por ele a o tamanho do aplicativo vai aumentando....
vc sugere alguma coisa com relacao ao rv.LocalReport.Render(
Nao adianta eu dar dispose... cada vez que passo por ele a o tamanho do aplicativo vai aumentando....
Acho que se o problema é do componente mesmo fica difÃcil fazer alguma coisa.
Talvez seja o caso de procurar alguma alternativa para ele.
Uma solução paliativa seria separar isso em um outro executável, o seu programa principal poderia chamar o executável que gera o PDF passando algumas informações por linha de comando, este executável geraria apenas 1 pdf e finalizaria, então seu programa principal só precisaria chamar ele em um loop, de preferência esperando cada um terminar de executar antes de chamar o próximo.
Desta forma como o executável que gera o PDF é finalizado a cada PDF que foi gerado não teria o problema de memória.
As desvantagens ai acho que seriam a de pode'r dar um pouco mais de trabalho para fazer desta forma e de que provavelmente deve ser um pouco mais lento que fazer tudo de uma vez.
Talvez seja o caso de procurar alguma alternativa para ele.
Uma solução paliativa seria separar isso em um outro executável, o seu programa principal poderia chamar o executável que gera o PDF passando algumas informações por linha de comando, este executável geraria apenas 1 pdf e finalizaria, então seu programa principal só precisaria chamar ele em um loop, de preferência esperando cada um terminar de executar antes de chamar o próximo.
Desta forma como o executável que gera o PDF é finalizado a cada PDF que foi gerado não teria o problema de memória.
As desvantagens ai acho que seriam a de pode'r dar um pouco mais de trabalho para fazer desta forma e de que provavelmente deve ser um pouco mais lento que fazer tudo de uma vez.
Beleza Ocelot,
Pensei nisto tbm criar um exe que é invocado e se fecha assim que cumpre sua missão.
Mas realmente vai dar um trabalho e ainda vou ter que fazer algum controle para garantir que o boleto gerou com sucesso.
No caso vc imaginou um exe que aceita parametros ao ser chamado ex: geraboleto.exe /pdf/c: este.pdf?
ai no caso apesar de salvar a memória, a performance cai pq toda vez que executo
reportviewer rv = new reportviwer perco milisegundos preciosos.
no meu sistema dou apenas uma vez o new e mando bala na geraçao.
tentei fazendo new varias vezes e dando dispose mas a memória vai embora do mesmo jeito. Só fechando a aplicação para voltar ao normal.
Obrigado!
abrs
Pensei nisto tbm criar um exe que é invocado e se fecha assim que cumpre sua missão.
Mas realmente vai dar um trabalho e ainda vou ter que fazer algum controle para garantir que o boleto gerou com sucesso.
No caso vc imaginou um exe que aceita parametros ao ser chamado ex: geraboleto.exe /pdf/c: este.pdf?
ai no caso apesar de salvar a memória, a performance cai pq toda vez que executo
reportviewer rv = new reportviwer perco milisegundos preciosos.
no meu sistema dou apenas uma vez o new e mando bala na geraçao.
tentei fazendo new varias vezes e dando dispose mas a memória vai embora do mesmo jeito. Só fechando a aplicação para voltar ao normal.
Obrigado!
abrs
Pensei em algo deste tipo mesmo, que no caso se não for muita coisa daria para passar por linha de comando mesmo os valores para gerar o boleto.
Garantir se foi gerado com sucesso ou não é até que simples, se você fizer tudo dentro do main() ele pode retornar um integer, que geralmente é esperado que se retorne zero, que significa sucesso, então você poderia retornar qualquer outro valor para dizer que falhou.
Então no outro programa você usa o objeto Process para executar e pegar o retorno, algo do tipo
Garantir se foi gerado com sucesso ou não é até que simples, se você fizer tudo dentro do main() ele pode retornar um integer, que geralmente é esperado que se retorne zero, que significa sucesso, então você poderia retornar qualquer outro valor para dizer que falhou.
public static int main(string[] args)
{
//gera o boleto
if (gerouComSucesso)
return 0;
else
return -1;
}
Então no outro programa você usa o objeto Process para executar e pegar o retorno, algo do tipo
var process = Process.Start([Ô]caminhodoexe.exe[Ô],[Ô]/destino=caminho /valorqualquer=exemplo[Ô]);
process.WaitForExit(); //isso vai travar o Thread até o outro programa retornar
if (process.ExitCode != 0)
{
//erro ao gerar
}
Beleza Ocelot!
Ahnnnn
Seu eu chamar um .exe consigo retornar o valor para o chamante? como se fosse uma função ou metodo?
Ahnnnn
Seu eu chamar um .exe consigo retornar o valor para o chamante? como se fosse uma função ou metodo?
Tópico encerrado , respostas não são mais permitidas