Lidando com recursos gerenciados e não gerenciados em .NET

Elemar Júnior

Podemos classificar os recursos utizados em .NET em duas categorias: gerenciados e não gerenciados.

Recursos gerenciados são desalocados automaticamente. Por outro lado, recursos não gerenciados dependem de uma estratégia adequada de desalocação explícita, geralmente implementada através do Dispose Pattern.

IMPORTANTE: É comum, entre os programadores .NET, associar do método Dispose()com liberação de memória. Entretanto, é importante destacar que, frequentemente, este não é o caso. Como iremos demonstrar, recursos não gerenciados podem ser de outros tipos.

O que são recursos gerenciados?

Quando falamos de recursos gerenciados estamos tratando, na prática, da memória gerenciada.

A memória gerenciada é aquela associada a objetos na heap que, quando não tem mais nenhuma referênica no código, são coletados, eventualmente, pelo Garbage Collector. Também estamos falando dos valores armazenados na stack que são desalocados quando há um descarte de um stack frame.

O que são recursos não gerenciados

Recursos não gerenciados são todos os recursos alocados pela aplicação, exceto a memória gerenciada.

Estão entre os recursos não gerenciados a memória alocada que não é controlada pelo Garbage Collector, como aquela alocada em rotinas escritas em C++. Também são recursos não gerenciados os handles de arquivos, sockets e outros recursos de rede, conexões com banco de dados, objetos GDI, etc.

Recursos não gerenciados geralmente são liberados através do método Dispose.

O método Dispose

Objetos que utilizam recursos não gerenciados geralmente implementam alguma estratégia de desalocação explícita desses objetos, geralmente através do método Dispose.

É importante lembrar que objetos não gerenciados não são desalocados automaticamente em .NET. Se um objeto implementa o método Dispose, então, este deve ser evocado explicitamente no código (ou implicitamente, através da utilização da instrução using).

Objetos que implementam o método Dispose, definido na interface IDisposable, deveriam implementar o Dispose Pattern.

Dispose Pattern

Dispose Pattern existe para garantir que objetos que utilizam recursos não gerenciados irão os descartar quando forem coletados pelo GC, mesmo que não tenham tido sua implementação para o método Dispose executada.

Abaixo, podemos ver um exemplo de implementação recomendada do dispose pattern proposta pelo Visual Studio:

O que o código relacionado ao Dispose Pattern faz?

Quando implementamos o Dispose Pattern, no método Dispose() executado sem parâmetros, chamamos o método Dispose(true) que, realizará as operações de liberação de recursos não gerenciados e também fará uma chamada ao método SuppressFinalize() do garbage collector, impedindo que este execute o finalizador para o objeto quando ele for coletado.

Se o programador esquecer de chamar o método Dispose explicitamente, então, eventualmente, o GC irá executar o finalizador e executará o Dispose(false).

NOTA: O método Finalize (finalizador) é executado pelo Garbage Collector sempre antes de descartar um objeto da memória gerenciada. Por isso, é uma boa ideia chamar o método Dispose no finalizador para garantir que recursos gerenciados serão liberados, mesmo quando o programador esquecer de chamar o método Dispose.

Cuidados ao definir código para um finalizador

Como indicamos, os finalizadores permitem definir código que será executado quando uma instância é descartada pelo GC. Entretanto, é bom lembrar que o GC opera de maneira não determinística, não sendo possível determinar quando o código do finalizador será, finalmente, executado. Assim, não podemos determinar, também, quando o recurso não gerenciado será finalmente liberado (no caso do programador cliente “esquecer” de executar o Dispose explicitamente).

Outro aspecto importante é que, por objetivar performance, o GC não descarta objetos, em Gen #0, que possuam finalizadores promovendo-os imediatamente para Gen #1. O que aumenta o custo do descarte.

NOTA: O método SuppressFinalize() “avisa” o GC que não é necessário executar o código do finalizador antes da coleta autorizando seu descarte em Gen #0,

Concluindo

É muito importante que saibamos identificar rapidamente recursos gerenciados e recursos não gerenciados. Recursos não gerenciados frequentemente não tem relação direta com memória alocada.

Sempre que utilizamos recursos não gerenciados, temos que projetar o descarte desses, preferencialmente de forma explícita pois ela não ocorrerá automaticamente.

Se um tipo contiver entre seus atributos um recurso não gerenciado, então deverá implementar a interface IDisposable.

A implementação de IDisposable respeitando o Dispose Pattern garante que recursos não gerenciados sejam sempre descartados.

Objetos que implementam finalizadores são mais custosos para liberar. Por isso, devemos lembrar de chamar o método Dispose explicitamente sempre.

Compartilhe este insight:

Comentários

Participe deixando seu comentário sobre este artigo a seguir:

Subscribe
Notify of
guest
5 Comentários
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Rogério dos Santos Fernandes
Rogério dos Santos Fernandes
3 anos atrás

Bem bom o POST! Curti!!

Antonio Maniero
Antonio Maniero
3 anos atrás

Só lembrando que *ref struct* em C# 8 permite ter um método *Dispose()*, sem implementar explicitamente a interface *IDisposable*, o que é uma espécie de *duck typing* da linguagem (não disponível para o programador criar seu próprio). E neste caso não envolve GC porque este tipo só pode ser alocado na *stack*.

Júlio Costa
Júlio Costa
3 anos atrás

Olá, tudo bem?
Achei muito interessante o post, mas fiquei com uma dúvida, quanto ao texto abaixo:

NOTA: O método Finalize (finalizador) é executado pelo Garbage Collector sempre antes de descartar um objeto da memória gerenciada.

Quem é esse método Finalize(finalizador)?
Quando vc diz finalizador, está se referindo ao destrutor da classe que tem a chamada para Dispose(false)?

Muito obrigado

Elemar Júnior
Elemar Júnior
3 anos atrás

Em C# não há destrutores. O método que “parece” o destrutor é, na prática, o Finalizer

Fabio Magalhaes
Fabio Magalhaes
1 ano atrás

Tenho uma classe, um Value Objetc (Lancamento) e o mesmo como atributo tem 3 List que sao manipulados por suas propriedades. Sempre q crio uma instancia desse VO eu popilos os atributos de tipo List ( public class LancamentosBloqueios : List, ILancamentos, IDisposable) e sempre que crio este VO eu carrego o mesmo para memoria. Minha duvida e devo implementar o IDisposabel na classe VO e no seu metodo dispose, chamar dispose para o LancamentosBloqueios?

AUTOR

Elemar Júnior
Fundador e CEO da EximiaCo atua como tech trusted advisor ajudando empresas e profissionais a gerar mais resultados através da tecnologia.

NOVOS HORIZONTES PARA O SEU NEGÓCIO

Nosso time está preparado para superar junto com você grandes desafios tecnológicos.

Entre em contato e vamos juntos utilizar a tecnologia do jeito certo para gerar mais resultados.

Insights EximiaCo

Confira os conteúdos de negócios e tecnologia desenvolvidos pelos nossos consultores:

Arquitetura de Dados

Insights de um DBA na análise de um plano de execução

Especialista em performance de Bancos de Dados de larga escala
Arquitetura de Software

Estratégias para modernização do legado

Desenvolvedor .NET/NodeJs e especialista em Kafka com experiência em startups e grandes empresas
Infraestrutura e Nuvem

Migração para a nuvem, mais do que mudança tecnológica, implica em mudança da cultura organizacional

Engenheiro de nuvem, arquiteto de software e especialista em Containers e Devops

Acesse nossos canais

Simplificamos, potencializamos e aceleramos resultados usando a tecnologia do jeito certo

EximiaCo 2022 – Todos os direitos reservados

5
0
Queremos saber a sua opinião, deixe seu comentáriox
()
x

Lidando com recursos gerenciados e não gerenciados em .NET

Para se candidatar nesta turma aberta, preencha o formulário a seguir:

Condição especial de pré-venda: R$ 14.000,00 - contratando a mentoria até até 31/01/2023 e R$ 15.000,00 - contratando a mentoria a partir de 01/02/2023, em até 12x com taxas.

Tenho interesse nessa capacitação

Para solicitar mais informações sobre essa capacitação para a sua empresa, preencha o formulário a seguir:

Tenho interesse em conversar

Se você está querendo gerar resultados através da tecnologia, preencha este formulário que um de nossos consultores entrará em contato com você:

O seu insight foi excluído com sucesso!

O seu insight foi excluído e não está mais disponível.

O seu insight foi salvo com sucesso!

Ele está na fila de espera, aguardando ser revisado para ter sua publicação programada.

Tenho interesse em conversar

Se você está querendo gerar resultados através da tecnologia, preencha este formulário que um de nossos consultores entrará em contato com você:

Tenho interesse nessa solução

Se você está procurando este tipo de solução para o seu negócio, preencha este formulário que um de nossos consultores entrará em contato com você:

Tenho interesse neste serviço

Se você está procurando este tipo de solução para o seu negócio, preencha este formulário que um de nossos consultores entrará em contato com você:

× Precisa de ajuda?