LIMPAR MEMÓRIA DE CLASSE INSTANCIADA

ICHIHARA 21/09/2015 17:48:52
#451655
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!
KERPLUNK 21/09/2015 18:44:57
#451657
Não adianta implementar a interface, tem que fazer uso de blocos using.
ICHIHARA 22/09/2015 10:33:53
#451677
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.
OCELOT 22/09/2015 14:55:20
#451693
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

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.
ICHIHARA 23/09/2015 08:43:04
#451731
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!
OCELOT 23/09/2015 10:18:31
#451733
A função Render que usei ali é a seguinte
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.
ICHIHARA 23/09/2015 13:55:47
#451740
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....
OCELOT 23/09/2015 15:31:54
#451743
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.
ICHIHARA 23/09/2015 17:28:21
#451748
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
OCELOT 23/09/2015 19:29:26
#451751
Resposta escolhida
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.
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
}
ICHIHARA 24/09/2015 17:07:55
#451807
Beleza Ocelot!
Ahnnnn
Seu eu chamar um .exe consigo retornar o valor para o chamante? como se fosse uma função ou metodo?
Página 1 de 2 [11 registro(s)]
Tópico encerrado , respostas não são mais permitidas