1. Este site usa cookies. Ao continuar a usar este site está a concordar com o nosso uso de cookies. Saber Mais.

Libertar memoria em c#

Discussão em 'Programação' iniciada por Galbne_PT, 16 de Agosto de 2006. (Respostas: 20; Visualizações: 8913)

  1. Galbne_PT

    Galbne_PT Power Member

    Boas ppl!

    Tenho um pequeno grande problema em C#, estou a desenvolver uma aplicação que gere reports de base de dados, ora, para fazer os reports com o formato pedido uso o crystalreports XI.
    O que se passa é k cada vez k mostro um report na aplicação a memoria do aumenta bastante ( uns 2 a 5 MB), mas todas a vez k fecho o form que contem o report a memoria mantem-se.

    Faço os Dispose() ao report e ao form mas mantem-se td na mm :(

    Uso outros resources para por a aplicação mais "user friendly" e faço os disposes a td...

    Tive a pesquisar na net sobre o garbage collection do .net, mas n encontra nd significativo que resolva esse problema.

    Alguém faz alguma ideia como posso diminuir o tamanho da memoria? (em testes já xeguei aos 100MB :confused: )

    Cumps,
     
  2. iznougud

    iznougud I quit My Job for Folding

    Isto VB.Net, mas deves conseguir converter para C#

    Public Class MemoryManagement

    Private Declare Function SetProcessWorkingSetSize Lib "kernel32.dll" ( _
    ByVal process As IntPtr, _
    ByVal minimumWorkingSetSize As Integer, _
    ByVal maximumWorkingSetSize As Integer) As Integer

    Public Shared Sub FlushMemory()
    GC.Collect()
    GC.WaitForPendingFinalizers()
    If (Environment.OSVersion.Platform = PlatformID.Win32NT) Then
    SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, -1, -1)
    End If
    End Sub

    End Class

    depois so tens de criar um objecto da class MemoryManagemente e executar o Flush:

    Dim mm as new MemoryManagement
    mm.FlushMemory()
     
  3. Hipnoted

    Hipnoted Power Member

    Não sei se dá para escrever C em C#, mas se der usa o free().

    Ex: free("variavel");
     
  4. SoundSurfer

    SoundSurfer Power Member

    Não tem nada a haver :)
    No C# (como no JAVA) a memória é limpa automáticamente pelo Garbage Collector.
     
  5. Galbne_PT

    Galbne_PT Power Member

    Pois, é limpa pelo Garbage Collector, até ele limpar a memória vai sp aumentando :(

    Teoricamente( visto em documento a falarem sobre o assunto) qd qualquer objecto deixa de ser referenciado é limpo qd o GC executa um processo .net interno para o efeito. (já tive mais de 2 horas com a aplicação a corre após fazer alguns teste e a memoria igual >()

    Será que demora mais de 2 horas, hum.. n deve ser, digo eu.
    N sei se estou a fazer alguma mal em codigo, mas o dispose() é a maneiera correcta para libertar os objectos? Fica mais uma pergunta no ar :D

    Amh vou tentar a solução do iznougud e dps digo os resultados,

    Cumps e obrigado a tds!
     
  6. Galbne_PT

    Galbne_PT Power Member

    Consegui converter para c#, pouca coisa tive de fazer em .net é quase td igual :P, a baixo segue o codigo em C# :D

    public class MemoryManagement
    {
    [DllImport("kernel32.dll")]
    private static extern int SetProcessWorkingSetSize(IntPtr process,int minimumWorkingSetSize,int maximumWorkingSetSize);

    public MemoryManagement()
    {
    }

    public void FlushMemory()
    {
    GC.Collect();
    GC.WaitForPendingFinalizers();
    if (Environment.OSVersion.Platform == PlatformID.Win32NT)
    SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, -1, -1);
    }
    }


    E resolve o problema, pelo menos liberta memoria :D

    Obrigado a tds e em especial ao iznougud pela solução

    Cumps,
     
  7. CoolZero

    CoolZero Power Member

    Não precisas de libertar memória nenhuma no C#, para isso existe o garbage collector.

    Se há várias razões pelas quais o C# é melhor, uma delas é precisamente isso. Ou seja, deixas de usar um objecto e não tens de fazer free à memória que ele usava. A vantagem disto é que, com o garbage collector o processo torna-se bastante mais rápido.

    O que acontecia anteriormente era que as pessoas tinham de andar a fazer free's à memória, agora o garbage collector deixa acumular um certo número de objectos a limpar e depois faz o free todo junto, poupando assim bastante tempo... mas bastante tempo mesmo!!

    http://www.samspublishing.com/articles/article.asp?p=101373&seqNum=13&rl=1

    Se quizeres forçar a limpeza de memória:

    Mas é como te digo, é uma perda de tempo fazeres isto.
     
  8. Galbne_PT

    Galbne_PT Power Member

    CollZero é td verdade o que dizes, todos os textos que li sobre o assunto dizem para deixar o Garbage Colletor tratar do assunto de libertar a memória, mas como disse anteriormente após alguns testes e ao fim de 2 horas com a aplicação aberta a memoria era a mesma :( isso sem minimizar a aplicação (qd minimizas ele faz o System.GC.Collect), ora uma aplicação com 70/80MB de memoria n posso permitir que tal aconteça e ainda por cima é memoria lixo, porque os objectos estão tds prontos para serem limpos simplesmente n são.

    Perco eficiencia, mas pelo menos liberto memoria para outras aplicações correrem à vontade e n "dizerem" que a minha aplicação ocupa mt memoria e n deixa os outros correrem :D

    Cumps,
     
  9. CoolZero

    CoolZero Power Member

    Tens de compreender que se o sistema não está a necessitar dessa memória, ela estar ocupada ou não é competamente indiferente. Ou seja, o pior que pode acontecer é um programa qq necessitar de memória e ela será liberta nessa altura.
     
  10. NoMercy

    NoMercy Power Member

    Galbne_PT:
    O problema não é com C# é com o Cristal Reports.
    Tive o mesmo problema com o Cristal Reports numa aplicação que desenvolvi e experimentei várias versões do Cristal Reports e sempre com o mesmo resultado: por cada vez que é utilizado, "come" memória. Este aumento de memória acontece quando se faz o setdatasource(object) do Cristal Reports.
    No meu caso, como tinha que gerar muitos reports sequêncialmente a aplicação acabava por rebentar com "out of memory exception" gerado pelo código do setdatasource(object) do CR.
    O problema é que embora as dll's do Cristal Reports que se referência serem .NET e portanto, serem managed code, as dll's em que o Cristal Reports está implementado são numa linguagem unmanaged code #1 (provavelmente C e C++) e é algures dentro destas dll's que os recursos utilizados não são libertados.

    #1 As dll's do Cristal Reports referênciadas no visual studio são apenas uns wrappers ("pontes") em .NET para as dll's que realmente contêm o código do Cristal Reports numa linguagem unmanaged code.
     
  11. ShadeX

    ShadeX Power Member

    De qqr modo, a ideia de que um garbage collector é obviamente melhor que um humano, é basicamente errada. A ideia é como a de que os optimizing compilers criam sempre melhor assembler que o melhor coder humano, e sabemos todos que isso é falso.

    Os garbage collectors fazem um trabalho semelhante ao dos optimizing compilers. O de reduzir o fosso entre os coders médios e os realmente bons. Lamentavelmente, nem de perto nem de longe lá chegam.

    Como tu dizes CoolZero, a mem não está a ser usada. A questão é que provavelmente um humano poderia tê-la liberto durante idle time do cpu quando não estava a ser feito nada, e o GC pode deixar passar a oportunidade e ter de fazê-lo durante 100% Load, quando menos convem. Em vez de aproveitares uma janela de oportunidade para fazer o cleanup, vais fazê-lo quando menos devias, pq o sys precisou da mem e o GC vai ter de "dá-la".

    Soluções automágicas são porreiras mas raramente funcionam de modo brilhante. Era melhor ensinar o ppl a fazer as coisas direitas. SCSI Scam com periféricos que se estavam borrifando, Plug'n'Play com devices que continuavam a fazer o que queriam, been there done that. O Autoconfig funcionava bem no Amiga pq tinhas 256 IRQ's para 4/6 placas... E ainda assim tarda não calha tinhas de fazer swap de algumas... E tens pilhas de bons exemplos de boas ideias "automágicas" que não funcionaram, é só procurar.
     
  12. Galbne_PT

    Galbne_PT Power Member

    Já suspeitava que o problema fosse mm do crystal, mas como são .net(esta no manual, n é que o tenha lido de cima a baixo :P).
    Mt mal que a microsoft seja :002: :lol:
    n podia dizer que um produto na teoria faça uma coisa e dps na pratica n faz.

    Concordo :P

    Cumps
     
  13. CoolZero

    CoolZero Power Member


    Básicamente o problema é q 99.9% dos programadores não sabe quando é essa janela de oportunidade que tu falas, logo vão fazer free à memória em alturas pouco convenientes. Isto já foi abordado em vários "encontros"/congressos acerca de framework .net. Normalmente quando alocas a memória vais liberta-la no final da função ou mal saibas q não a vais usar mais, n tens um array de ponteiros/objectos (tipo trash can) ao qual recorres para libertar memória assim que sabes que é a altura ideal.

    Um exemplo muito simples para verificares como é ineficiente fazeres tu os frees, se bem q é um exemplo um pouco a puxar a brasa para a framework, é teres um código simples como:

    Código:
    int main()
    {
        char* str;   
        while(true)
        {
           str = malloc(sizeof(char)*256);
           printf("%s", str);
           free(str);
        }
    }
    
    agora em C#

    Experimenta correr este código em máquinas iguais e vê a diferença de velocidade entre um e outro. Básicamente o free está a consumir muito tempo.. enquando na framework n é libertada a memória logo, por isso vês as coisas serem feitas muito mais rápidamente.
     
  14. ShadeX

    ShadeX Power Member

    Puxar a brasa é pouco. O primeiro exemplo força um free a cada ciclo, o segundo liberta quando o GC se lembrar. Experimenta meter um force no 2º e logo vês como o GC se comporta bem... E qual é a diferença real entre uma coisa e outra. Uma coisa é tu libertares a ram que sabes que não precisas, outra é um GC a "varrer os cantos á casa" á procura dela.
     
  15. CoolZero

    CoolZero Power Member

    Também n é assim, o GC n anda à procura pelos cantos da casa do q libertar. À partida existe uma série de objectos não referenciados em memória que ele sabe que pode libertar.
    Quanto ao exemplo era mesmo isso que queria dizer... em C tu forças os frees e, embora não seja dentro de um ciclo assim, é em alturas que não são as mais convenientes, pois se fosse mais tarde terias de andar a guardar as referencias paras os objectos que querias libertar.
     
  16. Galbne_PT

    Galbne_PT Power Member

    ShadeX e CoolZero vejo que cada um bem a sua opiniao e a qual são opostas, ao qual respeito.

    É mt positivo estarem a mostrar as suas opinioes e divergencia relativo ao tema.

    Mas, como sei pouco de GC, gostava de deixar mais uma pergunta. Relativo a meu caso pratico,
    eu optei por forçar o GC limpar a memoria depois de mostrar os reports, pois são eles que ocupam mais memoria.
    A pergunta é....
    Não é melhor forçar o GC, mm sendo ineficiente, mas para o utilizador do windows (mais propriamente o meu patrao) ver a aplicação com 10/15MB do que 70/80MB?
    Perde-se perfomance, mas o utilizador n nota mt.

    É a portuga, coisas bonitas, mm n sendo boas, são as k têm mais sucesso :P

    Obrigado desde já por tds as respostas.

    Cumps.
     
  17. ShadeX

    ShadeX Power Member

    Ou seja, tinhas de andar a fazer o trabalho do GC, com a diferença que podias tomar decisões mais "á medida" ,)

    Sabes, nos dias de hoje, já nem sei a razão de ser de discussões destas. Tens ram ao pacote, tens hd ao pacote, tens um OS que facilita tudo e mais alguma coisa...

    Provavelmente não tiveste o "previlégio" de trabalhar com um OS tipo AmigaOS. Não havia protecção de memória, não havia memória virtual, não havia muito de nada... Alturas em que 4MB era um luxo do cacete e um bad pointer limpava o OS e tudo o resto. Curiosamente, tinhas montes de apps a funcarem bem, tão rápido quanto podiam, a dar-se bem umas com as outras, a partilhar o pouco que tinham. Tinhas developers a sério tbm. Atm tens OSs/APIs que te protegem de tudo, que limitam o que podes fazer para não asneirares, que te forçam a fazer o que não queres "por questões de segurança", etc etc etc... E tens mais patches post-release que nunca, pq niguem testou a sério a coisa, e quando sai do dev env e vem para o mundo real, a bronca é do cacete...

    Galbne_PT:

    Eu sinceramente não me importo com a RAM, a menos que se torne um problema. E se vais forçar o GC, tenta fazer isso com pés e cabeça. Tens counters de cpu usage, checka primeiro os bixos. Nada mais maravilhoso que tu tentares libertar RAM enquanto uma app está a tentar fazer alguma coisa.
     
  18. CoolZero

    CoolZero Power Member

    Não cheguei a trabalhar com AmigaOS, só mesmo com Unix/Linux em que muitas das optimizações que fazia não eram propriamente ao nível do espaço mas sim ao nível da performance de execução. Acredito que nesses tempos fosse bastante importante o contrário, demorar o tempo que for necessário, mas ao menos ser feita qq coisa :) Apanhei com mts segmentation faults ;) Ou seja, a protecção de memória a funcionar :)

    Só trabalhei com endereçamento real quanto programei em Assembly para 8086, mesmo assim corria num simulador, não apagava nada que não fosse importante a não ser coisas minhas.

    Mas hoje em dia, com os sistemas operativos existentes, não há necessidade desse tipo de coisas, até porque a protecção de memória veio responder a 99% dos ataques que eram executados nos computadores, para além das asneiras. Mas lá está, antigamente quando necessitavas de gerir a memória, muito dificilmente o fazias de forma eficiente, hoje, como não tens essa necessidade, fazes as coisas de forma "mais" eficiente.

    Galbne_PT, tal como o Shadex disse, podes verificar primeiro o nível de cpu usado... ou então aproveitar o terminar de alguns eventos em que sabes que o utilizador acha "normal" existir um tempo de espera... Por exemplo, quando carregas num botão e a aplciação fica um ou dois segundos sem fazer nada, é desagradável, pensas q n carregaste no botão e vais lá carregar várias vezes :P portanto essas não são boas alturas, contudo, quando fechas uma janela, por exemplo a do crystal report, pode muito bem demorar um segundo a fechar... (convém pores o cursor sempre em ampulheta)
     
  19. ShadeX

    ShadeX Power Member

    Pensa num *nix com menos OS. E de acordo com as más linguas, um cadito mais organizado. Aliás, a grande cena do AmigaOS, mesmo defunto, é que na altura pegou nos fundamentos de *nix, massajou e compactou os ditos e fez-se qqr coisa de impressionante. O teu Win actual é uma tentativa mais ou menos bem sucedida de passar de uma legacy de m***a dos tempos do MSDOS para uma coisa mais sólida, ...tipo... *nix :D

    Se quiseres ver como era, experimenta o WinUAE. Se quiseres ter uma ideia de como era duro, corres em emul fiel de A500. E ficas a pensar como raio se fez aquilo... 512K de OS em ROM, 512K de RAM, uma disquete de 800K, um cpu de 7Mhz, presto, preemptive multitasking com GUI e tudo... E o desktop azul e laranja nem era muito mau nos 80's :P Mas pronto, dos fracos não reza a história, e a máquina (marca) não aproveitou a janela de oportunidade que teve. Fica para a história no entanto.
     
  20. inginheiiro

    inginheiiro Power Member

    GC

    True.

    Neste caso especifico deves usar o Garbage Collector.
    Repito: normalmente não deves usar o GC, mas este Interop (Wrapper para com) necessita de ser libertado excepcionalmente.

    no fim das tuas funções, coloca os objectos previamente instanciados a null. (good practice)
    no unload da tua form/web form. coloca GC.Collect();

    /ing
     

Partilhar esta Página