
Introdução
O sistema operacional Palm OS possui basicamente dois tipos de memória utilizados pelos aplicativos: Memória de Alocação Dinâmica e Memória de Armazenamento. A Memória de Alocação Dinâmica, conhecida por HEAP, é a memória utilizada para armazenar todas as variáveis criadas pelas aplicações, no momento da execução, enquanto a Memória de Armazenamento, conhecida por STORAGE, é a memória onde estão gravados todos os programas e bancos de dados do Palm OS.
O tamanho dessas duas memórias não é padrão, e varia em cada PDA/SmartPhone, por exemplo, o Palm T|X possui aproximadamente 6 Mb de memória de alocação dinâmica (heap) e 64 Mb de memória de armazenamento (storage), enquanto o Treo 650 possui aproximadamente 5 Mb de memória de alocação dinâmica (heap) e 22 Mb de memória de armazenamento (storage).
Conceito
O Handheld Basic possui uma função interna chamada MemInfo, que nos permite obter informações sobre as duas memórias (heap e storage), de acordo com o parâmetro informado, que pode ser um destes:
hbMemHeapSize- Corresponde ao tamanho total da memória de alocação dinâmica (heap) em bytes;hbMemHeapFree- Corresponde a quantidade livre na memória de alocação dinâmica (heap);hbMemHeapMax- Corresponde ao maior bloco de memória livre na memória de alocação dinêmica (heap)* em bytes;hbMemStorageSize- Corresponde ao tamanho total da memória de armazenamento (storage) em bytes;hbMemStorageFree- Corresponde a quantidade livre na memória de armazenamento (storage) em bytes.
* O Palm OS automaticamente efetua a desfragmentação da memória de alocação dinâmica quando necessário. Ao criarmos uma variável que ocupe um tamanho maior que o maior bloco de memória disponível, o Palm OS efetua a desfragmentação, na tentativa de conseguir um bloco de memória com o tamanho necessário para a variável.
Exemplo de utilização:

Private Sub Button1_Click()
'Mostra a quantidade de memória heap disponível
MsgBox Format(MemInfo(hbMemHeapFree), "#.00") & " bytes livres."
End Sub
Garbage Collector
Enquanto a desfragmentação da memória é de responsabilidade do sistema operacional, a liberação de memória das variáveis que não estão mais sendo utilizadas na aplicação, é uma tarefa realizada por um serviço do Handheld Basic chamado Garbage Collector (ou Coletor de Lixo). O Garbage Collector, assim como em outras plataformas como Java e .NET Framework, é um serviço responsável em monitorar as variáveis criadas pela aplicação que não estão sendo utilizadas e efetuar a liberação de memória.
No caso do HB++, o Garbage Collector é uma rotina incorporada em cada arquivo .prc, que é executada de tempos em tempos, de acordo com um algoritmo interno do Handheld Basic. O Garbage Collector não é executado muitas vezes, para não prejudicar a performance da aplicação, mas normalmente é executado vezes suficientes para que as aplicações tenham sempre memória disponível. Dessa forma, não podemos prever exatamente quando o Garbage Collector será executado.
Como o sistema operacional Palm OS não é multi-tarefa, este serviço não é executado em paralelo, como acontece em Java e .NET Framework, então nossa aplicação deixa de funcionar por alguns milissegundos, até que o Garbage Collector termine sua execução. Entretanto, esta pausa na aplicação normalmente é imperceptível, pois para não prejudicar a performance da aplicação, o Garbage Collector normalmente é executado por apenas 10 milissegundos, liberando a memória que conseguir, neste tempo.
Embora não seja possível prever exatamente todas as vezes que o Garbage Collector será executado, existe uma regra no algoritmo em que a cada 64 alocações de memória, o Garbage Collector é executado. Antes disso ocorrer, existem três situações que podem causar a execução do Garbage Collector:
- Quando existem blocos de memória que não estão sendo utilizados, e o usuário não efetuou nenhuma ação na aplicação por mais de 2 (dois) segundos (Idle time);
- Quando o espaço disponível no heap é insuficiente para satisfazer uma nova alocação de memória;
- Quando o Garbage Collector é executado explicitamente, através da função
MemCompact.
A função MemCompact só deve ser utilizada em casos extremos, onde seja necessário alocar e liberar uma grande quantidade de memória, e o tamanho do heap seja limitado. Na maioria dos casos, não é necessário executar o Garbage Collector explicitamente, e devemos deixar o algoritmo decidir o melhor momento, para garantir a melhor performance possível para as aplicações.
A função MemCompact recebe dois parâmetros do tipo Boolean, que são, respectivamente:
bGarbageCollector- Define se o Garbage Collector deve ser executado (TrueouFalse);bCompact- Define se a memória deve ser Desfragmentada pelo sistema operacional (TrueouFalse).
Exemplo de utilização:
Private Sub Button1_Click()
'Executa o Garbage Collector e Desfragmenta a Memória
MemCompact True, Tue
End Sub
Escopo de Variáveis
Toda variável possui um escopo que define onde ela pode ser utilizada, e qual seu tempo de vida. Variáveis criadas dentro de uma Function ou Sub, por exemplo, são válidas apenas dentro deste bloco, enquanto variáveis criadas dentro de classe, são válidas enquanto a instância da classe existir.
'Variavel criada no escopo da classe
Private m_VariavelDaClasse As String
Private Sub Button1_Click()
'Variável criada no escopo do método
Dim variavelDoMetodo As String
'Acesso à variavel local (do método) 'OK
variavelDoMetodo = "Botão 1"
'Acesso à variavel da classe 'OK
m_VariavelDaClasse = "Botão 1"
End Sub
Private Sub Button2_Click()
variavelDoMetodo = "Botão 2" 'ERRO DE COMPILAÇÃO
m_VariavelDaClasse = "Botão 2" 'OK
End Sub
No exemplo acima, ocorre o erro de compilação error #2201 : identifier 'variavelDoMetodo' is not defined, indicando que a variável variavelDoMetodo não existe no método Button2_Click, e deveria ser declarada, assim como no método acima, utilizando a instrução Dim. Já o acesso à variavel m_VariavelDaClasse é garantido, pois todos os métodos de uma classe podem acessar as variáveis que estão no escopo da classe.
Escopo de Variáveis e o Garbage Collector
O Garbage Collector só libera a memória de variáveis que não estão sendo mais utilizadas pelas aplicações, e para fazer este controle, ele cria uma lista com todas as variáveis utilizadas, mapeadas aos endereços de memória onde estão alocados os objetos.

'Variavel criada no escopo da classe
Private m_minhaTabela As tblMinhaTabela
Private Sub Button1_Click()
Dim Empresa As String
Empresa = "PDAExpert Tecnologia em Software"
Dim Website As String
WebSite = "http://www.pdaexpert.net"
Dim Telefone As String
Telefone = "+55 11 3374-3321"
Set m_minhaTabela = New tblMinhaTabela
m_minhaTabela.OpenTable hbModeReadWrite
'(...)
m_minhaTabela.Close
End Sub
No exemplo acima, quando a função Button1_Click termina a execução, todas as variáveis criadas dentro deste método deixam de existir, e a única variável que continua a existir é a m_minhaTabela, por estar no escopo da classe.

Embora as variáveis que pertenciam ao método deixaram de existir, todos os objetos instanciados continuam a existir, e continuam a ocupar espaço em memória, até que o Garbage Collector seja executado e possa liberar a memória utilizada por estes objetos. No momento em que o Garbage Collector for executado, perceberá que os três primeiros objetos não possuem variáveis referenciando-os, e os removerá da memória.

A importância de atribuir "Nothing" às variáveis
No exemplo acima, podemos notar que a variável m_minhaTabela continua a existir, por estar dentro do escopo da classe, mas podemos notar também que a tabela foi fechada, e que o objeto alocado na memória não será utilizado novamente na aplicação. Mesmo assim, a tabela continuará ocupando memória até que este formulário seja fechado, que será quando a variável m_minhaTabela deixará de existir e somente assim o Garbage Collector poderá liberar a memória ocupada pelo objeto.
Nestas situações, devemos atribuir Nothing à variável, para eliminarmos a referência que ela faz ao objeto, na tabela do Garbage Collector:
'Variavel criada no escopo da classe
Private m_minhaTabela As tblMinhaTabela
Private Sub Button1_Click()
'(...)
Set m_minhaTabela = New tblMinhaTabela
m_minhaTabela.OpenTable hbModeReadWrite
'(...)
m_minhaTabela.Close
Set m_minhaTabela = Nothing
End Sub

Dessa forma, a variável m_minhaTabela continuará a existir, pois ainda está no escopo da classe, mas já não referencia o objeto alocado em memória, e assim permitirá que o Garbage Collector libere este bloco de memória, quando for executado.
Memória de Armazenamento
Diferentemente da memória de alocação dinâmica, a memória de armazenamento não possui um serviço como o Garbage Collector para liberação de memória. O funcionamento dessa memória é parecido com o funcionamento de um disco rígido de um computador, ou um pen drive, por exemplo. Quando instalamos aplicações e/ou inserimos registros em bancos de dados, o espaço vai sendo ocupado, e quando desejarmos liberar espaço, temos de apagar arquivos e/ou registros dos bancos de dados.
Histórico
- 18/05/2007 - Primeira versão deste artigo.
Sobre o Autor
Caio Proiete é Arquiteto de Soluções, especialista em desenvolvimento de softwares para PDAs e telefones celulares, principalmente nas plataformas Palm OS, Windows Mobile e Symbian OS.
Atualmente suas principais ferramentas/tecnologias de trabalho incluem CodeWarrior C++, Handheld Basic, eMbedded Visual C++, .NET Compact Framework, C# .NET, e Carbide.c++.
Possui extensa experiência em arquitetura e desenvolvimento de sistemas baseados em web e smart-clients, gerenciamento de projetos e treinamento, e atua também como instrutor oficial Microsoft em centros de treinamentos (CLPS), e é detentor das seguintes certificações:
- MCT - Microsoft Certified Trainer;
- MCSD - Microsoft Certified Solution Developer;
- MCDBA - Microsoft Certified Database Administrator;
- MCAD .NET - Microsoft Certified Application Developer;
- MCSD .NET - Microsoft Certified Solution Developer for .NET;
- MCTS - Microsoft Certified Technology Specialist for Windows Mobile.
Veja o todos os artigos publicados por Caio Proiete no PDAExpert.
Artigos Relacionados
- Não existem artigos relacionados
4 Comentários »
Comentários via RSS TrackBack URI
-
Audrey Marcos em 19/05/2007 10:05
Parabéns à você Caio pelos excelentes artigos sobre HB++ que vem disponibilizlando neste site.
Tenho aprendido muito com estes artigos.Se possivel, gostaria de ver um artigo sobre o gerador de conduits no HB++
—Esse conduit poderia ter uma string de conexâo com o FireBird ?? -
Alberto Rodrigues em 03/06/2007 10:45
Parabéns pelas informações dadas. Estou iniciando na área de programação em PDA’s possuo um Palm Life Drive e gostaria de desenvolver soluções voltadas para engenhearia elétrica , minha área de formação, para tanto necessido saber onde consigo os programas citados nos seus artigos … gostaria de saber quais vou realmente precisar …
Tais como:
CodeWarrior C++
Handheld Basic
eMbedded Visual C++
.NET Compact Framework
C# .NET
Carbide.c++.Obrigado . Alberto Rodrigues
-
Equipe PDAExpert em 03/06/2007 13:48
Caros Usuários,
A área de comentários deve ser utilizada para dúvidas sobre o artigo em questão.
Para dúvidas não relacionadas com o artigo, utilizem nosso fórum.Atenciosamente,
Equipe PDAExpert
www.pdaexpert.net -
Leonardo em 29/11/2007 17:12
Parabens, pelo tutorial.
Faltou falar um pouco sobre o projeto que esta disponivel para download, sua aplicação não me foi muito clara!


Envie seu comentário
ATENÇÃO: A área de comentários deve ser utilizada apenas para dúvidas sobre este artigo. Para dúvidas não relacionadas a este artigo, utilize o Fórum PDAExpert.net.