Post: Resolvendo Vazamento de Memória em Injeção de Dependência

Alessandro Medeiros

Muitos programadores não se atentam para o vazamento de memória e às vezes indagam o porquê de seu aplicativo está aumentando muito o consumo de memórias, não se preocupam com o controle desse vazamento.

Mas afinal de contas o que é vazamento de memória?

O vazamento de memória ou Memory leak, é um fenômeno que ocorre quando uma porção de memória, alocada para uma determinada operação, não é liberada quando não é mais necessário. A ocorrência de vazamento de memória é quase sempre relacionada a erros de programação e pode levar a falhas no sistema se a memória for completamente consumida. O ReportMemoryLeaksOnShutdown nos ajuda a identificar esse vazamento para que possamos trabalhar e corrigir esses problemas.

Por padrão nos compiladores de desktop as interfaces usam contagem de referência. À medida que você atribui uma variável à interface, a contagem de referência é aumentada e quando é definida como nula ou sai do escopo, a contagem de referência é diminuída.

Quando a contagem de referência chega a zero, o objeto é excluído da memória. Isso não é sempre verdade, já que o comportamento real é implementado por cada classe, assim você pode escrever uma classe que implemente uma interface e ignore o mecanismo de contagem de referência.

Primeiro vou te mostrar como isso pode causar problemas para você.

Já ouviu alguém falando que quando você usa Interfaces você não precisa destruir os objetos que eles se destroem sozinho? E tudo isso sem Memory Leaks.

Bom nem sempre isso é verdade, vou te mostrar um caso onde as interfaces não

conseguem se entender sozinhas.


type
    iNota = interface
        ['{B4381A5C-0F70-420C-B369-D07A4CE4C3C1}']
    end;

    iNotaItens = interface
        ['{345B9240-4AB6-4F58-8C94-7A5E161B21BB}']
    end;

    TNota = class(TInterfacedObject, iNota)
        FItens : iNotaItens;
        constructor Create;
    end;

    TNotaItens = class(TInterfacedObject, iNotaItens)
        private
            FNota : iNota;
        public
            constructor Create(Parent : iNota);
    end;

Um Fluxo simples onde a classe de Nota referência os Itens da Nota, e por sua vez a classe de itens precisa saber de qual nota eles pertencem então, recebe por injeção de dependência o objeto de Nota.

Neste caso o contador de referência aumenta pois a classe TNota já cria a instancia de Itens da Nota:


constructor TNota.Create;
begin
    FItens := TNotaItens.Create(Self) as iNotaItens;
end;

e como temos a necessidade de instanciar a interface iNota na variável FNota na classe TNotaItens, e em seu create passamos por referência:


constructor TNotaItens.Create(Parent: iNota);
begin
    FNota := Parent;
end;

Se o mundo mágico das interfaces funcionasse do jeito que é falado, isso não causaria nenhum problema, porém quando referenciamos a Nota dentro do NotaItens o contador de referência entra em ação e adiciona mais uma referência ao objeto, e com isso… ao fecharmos o projeto…

Isso mesmo, temos um memoryleak, não precisa fazer nada, basta instanciar o Objeto de Nota e ao fechar o projeto temos esse memoryleak


procedure TForm3.FormCreate(Sender: TObject);
begin
    ReportMemoryLeaksOnShutdown := true;
    Nota := (TNota.Create as iNota);
end;

Existe um jeito de resolvermos isso… usando o atributo [weak]


private
   [weak]
   FNota : iNota;

As referências weak evitam aumentar a contagem de referência, mas ela é gerenciável. Isso significa que o sistema controla as referências weak e, no caso do objeto real ser excluído, ele definirá a referência weak como nula, assim não incrementando o contador de referência.

A referência weak é usada para quebrar esse ciclo que mantém um ao outro vivo. Isso é feito declarando-se uma referência como um ponteiro puro para contornar o mecanismo de contagem de referência.

Isso é Fantástico, porém só existe nas versões mais recentes do Delphi…

é nesse momento que você entra em desespero…

“Eu não utilizo as versões mais recentes do Delphi, como posso fazer?”

Para isso temos que referenciar utilizando Ponteiros dessa forma:


class procedure TInjection.Weak(aInterfaceField: Pointer;
    const aValue: IInterface);
begin
    PPointer(aInterfaceField)^ := Pointer(aValue);
end;

No Create da classe TNotaItens vamos trabalhar com os ponteiros para não incrementamos o contador de referência e sim apontarmos para um mesmo endereço de memória, dessa forma evitamos o memory leak ao fecharmos o projeto.

Para auxiliar nesse processo eu desenvolvi uma classe simple chamada TInjection que eu utilizo em todos os meus código, ela já facilita esse processo para mim, com ela o código fica bem mais limpo como você pode ver abaixo:


constructor TNotaItens.Create(Parent: iNota);
begin
    TInjection.Weak(@FNota, Parent);
end;

Essa classe você pode baixar no link abaixo juntamente com todos os fontes desse artigo:

BAIXAR OS FONTES DO ARTIGO

 

 

Esse artigo foi retirado de uma das aulas do nosso treinamento de POO Avançado e Programação Funcional, nesse treinamento você irá aprender de forma prática, técnicas que irão te ajudar a ter um código bem estruturado, organizado e preparado para as mudanças repentinas, afinal sabemos que a todo o momento seja por força do governo ou por solicitações de clientes, precisamos realizar alterações em nossos projetos, então porque não ter um código já preparado para essas mudanças? No treinamento, eu desenvolvi um método que alinha exemplos reais de aplicação das técnicas para resolver problemas do dia a dia, Como:

* Reutilização de código

* Fácil adaptação a novas tecnologias / componentes

* Fácil implementação de novas features

* Até 70% de redução no tempo de manutenção do código

* Redução de Bugs na entrega de novas implementações

SAIBA MAIS SOBRE O CURSO POO  AVANÇADO E PROGRAMAÇÃO FUNCIONAL CLICANDO AQUI

Faça sua busca

CATEGORIAS

POSTS RECENTES

E caso você tem interesse de conhecer mais sobre Resolvendo Vazamento de Memória em Injeção de Dependência, acesse o nosso portal do CLUBE DE PROGRAMADORES EM DELPHI
Você não terá só conteúdos relacionados ao Resolvendo Vazamento de Memória em Injeção de Dependência, mas uma quantidade enorme de conteúdos que poderá lhe ajudar muito no seu dia a dia, é uma verdadeira NETFLIX para os programadores Delphi.
Gostou?
Compartilhe:

Embarque no foguete com milhares de devs para aprender desenvolvimento, evoluir de forma contínua e se manter relevante no mercado.

Sobre
Dúvidas
Cadastre-se em nossa lista

Para ter acesso em primeira mão, a tudo que acontece na Academia do Código, basta se cadastrar em nossa lista

Grupo Thulio Bittencourt | Academia do Código

#FaçaPartedaHistória

Copyright © 2022 – Todos os direitos reservados