VB .NET - Otimizando o Garbage Colector - GC.
O coletor de lixo (garbage collector) conhecido também como gc, é usado para retirar objetos instanciados na memória mas que não estão sendo mais usados(referenciados). Este recurso, disponível na Linguagens .NET permite que você otimize o seu código, deixando ele mais rápido, e com isso ganhando produtividade O que o gc efetua é na verdade um gerenciamento automático de memória que automaticamente libera blocos de memória que não serão mais usados em uma aplicação.
Algumas
estratégias de alocação de memória: Estática: As áreas de memória são alocadas antes do início do programa; não permite mudanças nas estruturas de dados em tempo de execução (Ex: Fortran) Linear: memória alocada em fila ou em pilha; não permite remoção de objetos fora da ordem de criação (Ex: Forth) Dinâmica: permite liberdade de criação e remoção em ordem arbitrária; requer gerência complexa do espaço ocupado e identificação dos espaços livres (ex: Java, C++,C#,.NET) |
As vantagens que podemos apontar em usar linguagens que disponibilizam este recurso como Java, C# e VB.NET são:
Mas nem tudo são flores pois o gc não é perfeito.
O processo de funcionamento do Garbage Collector, daqui pra frente chamado apenas de coletor ou gc, da plataforma .NET pode parecer a primeira vista misterioso e obscuro, uma caixa preta que funciona por sozinha e a qual parece que não temos acesso algum. Poderia um programador exercer algum controle sobre o processo de funcionamento do coletor de lixo ?
A resposta é : sim pode !
Existem situações nas quais o programador vai ter que executar o coletor de forma explicita chamando um dos métodos expostos pelo gc. Uma destas situações seria, por exemplo, após a criação de uma grande quantidade de objetos que foram usados para um fim específico e que não serão mais necessários. Neste caso porque esperar o gc entrar em ação se você pode fazer a faxina ? O gc funciona automaticamente mas você pode invocá-lo manualmente; desta forma, para destruir um objeto imediatamente você pode simplesmente digitar: System.GC.collect()
O objeto System.GC expõe diversos métodos que podem ajudá-lo ano processo de coleta do lixo, seja para um objeto específico ou para um sistema como um todo.
Quando você termina de usar um objeto atribuindo-lhe o estado como Nothing ou deixando-o de utilizar ele é incluído no sistema de coleta de lixo para uma eventual finalização e liberação. A finalização ocorre quando o método Finalize() do objeto é chamado. A liberação ocorre quando a memória alocada para o objeto é reclamada e disponibilizada para ser usada por outro processo gerenciado ou não gerenciado.
O coletor de lixo atua em ondas ou ciclos de geração. Quando um objeto entra pela primeira vez no sistema, ele aparece na Geração 0. Se depois de algum tempo o objeto ainda não foi finalizado ou liberado , ele é movido para a próxima geração, Geração 1. Nem todas as plataformas suportam este tipo de atuação. Para verificar você pode usar a propriedade System.GC.MaxGeneration e assim determinar a geração máxima de vida e um objeto. Para sistemas que não suportam este tipo de atuação o valor retornado será sempre igual a zero.
Você pode usar um dos seguintes membros do System.GC para ajudá-lo a gerenciar o sistema de coletor de lixo em aplicações com memória crítica:
Método | Descrição |
AddMemoryPressure() RemoveMemoryPressure() |
O sistema de
coletor de lixo esta relacionado somente com a memória
gerenciada que é a memória alocada através de
características da plataforma .NET. A memória não
gerenciada não entra no processo do coletor. No entanto
o processo de coleta toma a quantidade total de memória,
a gerenciada e a não gerenciada, em conta para
determinar como rapidamente liberar recursos. O método AddMemoryPressure() aceita como argumento um contador byte e diz para o coletor de lixo agir como se a quantidade de memória não gerenciada estivesse alocada. Dependendo do tamanho da pressão, o processo de coleta será processado de forma diferente devido as mudanças percebidas na memória disponível. Você precisa posteriormente reverter a pressão de alocação através do método RemoveMemoryPressure() usando o mesmo contador byte fornecido com a requisição de pressão inicial. Você pode ter diversas requisições de pressão ativas ao mesmo tempo. |
Collect | Este método força a coleta imediata (finalização e liberação) do lixo. Por padrão, este método coleta o lixo em todas as gerações. Você também pode passar o número da geração, e a coleta será feita somente entre a geração 0 e o número da geração informado como argumento. |
CollectionCount | Retorna um o número de vezes que o lixo foi coletado para um número de geração específico. O número de geração é passado como argumento |
GetGeneration | Se você tiver acesso a referência do objeto que já entrou no sistema de coleta, passando-o como um argumento para GetGeneration() , será retornado o número da geração no qual o objeto aparece. |
GetTotalMemory | Retorna uma estimativa do total da memória gerenciada alocada. Aceita um argumento booleano que se for True permite ao gc ocorrer antes que a estimativa seja calculada. |
KeepAlive | Normalmente ,
quando um objeto não esta mais referenciado , você não
se importa quando o processo do gc irá destruí-lo.
Contudo , se você alocar memória gerenciada que você
deseja compartilhar com um processo externo não
gerenciado (como uma função em uma DLL ActiveX), e este
processo irá usar a memória além do seu uso local, o
gc retardará processamento do objeto até ele não mais
existir. Este método ajuda a forçar um retardamento neste processo do gc. Para usar o método você passa a ele uma referência do objeto que deseja reter e você chama este método quando você não deseja mais retê-lo. KeepAlive mantém o objeto vivo até um ponto , a partir deste ponto ele vai para o gc. |
SuppressFinalize ReRegisterForFinalize |
Passando uma
referência de um objeto para SuppresFinalize() diz ao gc
para não chamar o método Finalize() deste objeto antes
de liberar o objeto. Este método é mais usado com
objetos que implementam a interface System.IDisposable.
Se voce limpar todos os recursos alocados durante a
chamada a Dispose(), não haverá mais nada para
finalizar, chamando SuppressFinalize() você não precisa
chamar Finalize(). Se você usar este método mas depois descobrir que você precisa habilitar novamente o processo de finalização para um objeto , chame o método ReRegisterForFinalize. |
RequestFinalizeOnShutdown | Método de trabalho implementado para se chamar um rotina de finalização. |
WaitForPendingFinalizers | Este método suspende a execução da aplicação até que todos os objetos relevantes no gc tenham o seu método finalize() chamados. |
MaxGeneration | Lista as gerações que o sistema pode suportar.Se não suportar exibe o valor 0. |
TotalMemory | Exibe o espaço total de byte de objetos referenciados, e podem sobrepor objetos que serão lançados em breve |
Nota: Quando você aciona System.gc(), não significa que o garbage collector entrará em ação, é apenas uma sugestão que você pode fazer a plataforma .NET;o GC não será executado em situações críticas do sistema, como falta de recursos, etc.
Vejamos a seguir dois exemplos de como você pode usar a GC. Todos os exemplos abaixo foram feitos no VB 2005 Express.
1- Forçar uma coleta
Abra o VB 2005 Express e crie um novo projeto do tipo Console Application com o nome de forcaGC
A partir do menu Project selecione a opção Add Class e informe o nome forcaGC.vb e a seguir inclua o seguinte código na classe:
Public
Class classePrincipal Shared Sub Main() Dim obj As MeuObjeto = New MeuObjeto obj = Nothing 'estou forçando uma coleta no objeto após liberá-lo GC.Collect() End Sub End Class ----------------------------------------------------------------------------------- Public Class MeuObjeto ' Construtor do objeto - É chamado quando o objeto é instanciado (new) Public Sub New() Console.WriteLine("Objeto " & GetHashCode() & " criado.") End Sub Protected Overrides Sub Finalize() ' Finalize - chamado quando o objeto é removido da memoria... MyBase.Finalize() ' avisa o usuário que vamos destruir o objeto Console.WriteLine("Objeto " & GetHashCode() & " finalizado.") End Sub End Class |
O resultado da execução do código ao lado
mostra o objeto criado e o mesmo Perceba que na classe estática (Shared) Main() o objeto é criado via palavra chave New. Desta forma o seu construtor é iniciado exibindo a mensagem de criação do objeto. Em seguida, na classe Main() , o objeto é liberando pela atribuição de Nothing ao mesmo. Em seguida forçamos o GC a entrar em ação e executar o método Collect(). Isto faz com que o método sobrescrito (Overrides)
Finalize seja chamado destruindo o objeto.
|
2- Exibindo a geração de objetos
Abra o VB 2005 Express e crie um novo projeto do tipo Console Application com o nome de generationGC.
A partir do menu Project selecione a opção Add Class e informe o nome generationGC.vb e a seguir inclua o seguinte código na classe:
Public Class Principal
'cria uma instância de Object Dim meuObjeto As Object = New Object()
Dim i
As
Integer Console.WriteLine(String.Format("Geração = {0}",GC.GetGeneration(meuObjeto))) 'força a coleta GC.Collect() 'aguarda que o objeto seja finalizado GC.WaitForPendingFinalizers() Next i End Sub End Class |
|
Com isto apresentei o GC a você , aguarde em breve mais artigos sobre este assunto...
Até o próximo artigo VB.NET
José Carlos Macoratti