Acelerando a sua aplicação Visual Basic 6


Sabe aquele "sisteminha" feito em VB que você levou uma semana para fazer e que demora 5 minutos para carregar. É... , aquele que quando você foi gerar os discos para distribuição teve que comprar duas caixas de disquetes. Lembra ?  Não ?? Então mais uma dica : aquele que quando vai carregar aquele grid com os dados dos clientes  dá tempo para ir tomar  um cafezinho e voltar ....

Exageros á parte , quem nunca ficou decepcionado com o desempenho de um sistema após gastar dias e dias no seu desenvolvimento ?  Neste artigo vamos tentar mostrar como:

1-) Diminuir o tamanho da sua aplicação ( dos arquivos)

2-) Limitar o uso da memória pelo VB 

3-) Aumentar e medir o desempenho da sua aplicação. 

Nem tudo são flores no VB

Quer fazer um teste ?  Promete que não vai ficar decepcionado ? Então vamos lá...:

1-) Inicie um novo projeto no seu VB

2-) Não insira nenhum controle no formulário padrão

3-) Não digite uma única linha de código 

4-) Salve o formulário padrão e o projeto com o nome de vb_1 (pode ser qualquer nome. Ex:faz_nada )

Compile e . usando o Package and Deployment Wizard , gere os discos de distribuição da  sua potente aplicação. 

Dê uma olhada no tamanho do programa EXE gerado . Algo em torno de 1,25 MB ....(Você deve estar achando lamentável ...)

Ao executar a aplicação , que faz absolutamente nada (lembre-se que não temos nenhum código no sistema), você irá perceber que a sua aplicação deverá estar usando uns 2 MB de memória do sistema... (A esta altura você deve estar se perguntando : Por que ?  Por que ? Por que ?)

O Porque e o Como...

Para começar , todos, eu disse TODOS, os programas feitos em VB 6.0 precisam da MSVBMV60.dll (na versão 50 o arquivo chama-se MSVBMV50.dll). Dê uma olhada no tamanho deste arquivo : 1,30 MB. E, pasme, você não pode fazer quase nada com relação a memória que esta dll utiliza. Para seu consolo vamos mostrar como você pode atuar para reduzir o consumo de memória e melhorar o desempenho :

1-) Quando você desenvolve uma aplicação no VB geralmente faz referências a OCX´s que o seu sistema utiliza. Pois bem , tudo que você referencia o seu projeto carrega junto com ele, por isso Referencie somente os objetos que realmente vai precisar. Você sempre vai precisar das seguintes referências:

-Visual Basic For Applications
-Visual Basic runtime objects and procedures
-Visual Basic objects and procedures
-OLE Automation

2-) Esteja certo de que a sua aplicação esta usando somente os componentes que realmente ela vai precisar. Assim se você referenciar o Microsoft Windows Common Controls para usar somente uma barra de progresso ( progress bar ) vai usar uma OCX - MSCOMCTL.OCX - com nada mais nada menos que 1.0 MB. Será que você não pode usar um controle de terceiros ( de preferência freeware) especifico para a tarefa que pretende realizar. Certamente ele será bem menor que a MSCOMCTL.OCX .

3-) Carregue somente os formulários que você vai usar. Se você não vai precisar de  um formulário rapidamente, prefira descarregá-lo da memória usando o comando Unload. O comando Hide embora agilize a exibição(Show) do formulário não o remove da memória. Aqui entra o bom senso: nada justifica carregar diversos formulários que não serão usados na memória .

4-) Coloque o seu código de preferência em classes e/ou formulários , eles podem ser criados e destruídos quando requeridos . Se você usar o seu código em módulos , ele será carregado ao iniciar o seu sistema quer você precise usá-lo ou não. 

5-) Tenha cuidado na declaração de variáveis. Se você vai tratar números de 1 a 256 use o tipo de dados Byte ao invés de Integer ou Long. O tipo Byte usa 1 byte de memória o Integer e o Long usam 4 bytes. Escolha o tipo correto e você esta economizando memória.

A questão da Compilação...

A partir da versão 5.o o VB oferece a opção de compilação em Native Code ou P-Code. Ao selecionar a compilação Native Code temos a possibilidade usar as otimizações conforme figura abaixo:

Vamos comparar a velocidade de uma aplicação com o código abaixo compilada segunda as diversas opções:

For I = 0 To 3000000 Step 0.1
    A = Sqr(I) + A
    z = A +1/ 32.34
Next

Obs: testes realizados em um pentium III 600 com 128 MB RAM.

Modo de compilação Tempo para execução(minutos)
Native Code - Fast Code 1.077
Native Code - Small Code 2.1745
Native Code - Fast Code (Favour Pentium) 1.7876
Native Code - Small Code (Favour Pentium) 1.9505
Native Code - No Optimization 2.4461
P-Code 2.5598
Run-time 3.0695

Já deu para perceber que , quanto a velocidade, o sistema compilado no modo P-Code é mais lento que o modo Native Code. Então para rodar mais rápido compile o seu projeto no modo Native Code.

E quanto ao tamanho ? Como será que a comparação quando compilamos com as diversas opções. Nosso projeto possui somente um formulário , um botão de comando , duas labels e o código acima. Veja abaixo

Modo de compilação Tamanho
Native Code - Fast Code 20KB
Native Code - Small Code 20KB
Native Code - No Optimization 20KB
P-Code 12KB

Deu para perceber que a compilação no modo P-Code gera um arquivo com menor tamanho. Como nosso projeto é pequeno , a diferença entre as opções  Native-Code praticamente não existiu. Se você pretende distribuir sua aplicação via Internet, o tamanho do arquivo poderá fazer a diferença. Embora mais lento,  o modo P-Code gera arquivos com tamanho menores.  Além do mais compilar no modo P-Code é muito mais rápido ... A decisão deverá ser baseada em como você vai fazer a distribuição da sua aplicação.

Generalizando...

A seguir algumas dicas de como melhorar o seu código para aumentar o desempenho de sua aplicação.

  1. Passe variáveis por valor ( ByVal ) ao invés de por referência ( ByRef) que é o padrão usado pelo VB. Assim o VB nao tem que enviar o endereço da variável e retorná-lo após a procedure ter sido chamada.

  2. Evite ficar refazendo e calculando as mesmas operações . Faça o cálculo e guarde o resultado em uma variável para depois usar a variável. Ex: Para saber o comprimento de uma string que você sabe que não irá mudar de tamanho não fique usando a função Len toda vez para calcular o tamanho.

  3. Prefira usar Select Case ao invés de If ElseIf , é muito mais rápido.

  4. Ao usar a função IF procure separar as decisões lógicas . Se a primeira expressão for Falsa , mesmo assim o VB ira avaliar a segunda expressão desnecessariamente. Assim:

    Private Sub Command1_Click()
        ' Mais lenta
        If f1 And f2 Then
            Debug.Print "True"
        End If
---------------------------------------------------------------------------------
        ' Mais rápido porque f2 nnão será executada quando f1 for Falsa ( false )
        If f1 Then
            If f2 Then
                Debug.Print "True"
            End If
        End If
    End Sub
  1. Avalie o resultado de funções diretamente para o controles . Assim se temos uma função VerificaSenha que retorna False/True, temos?
    If VerificaSenha = True Then
        cmdLogon.Enabled = True
    Else
        cmdLogon.Enabled = False
    End If
É mais lenta que ::
    cmdLogon.Enabled = (VerificaSenha = True)
Um código mais rápido seria::
    cmdLogon.Enabled = VerificaSenha
  1. Procure usar Controls Arrays para controles que você repete no formulário. Ex: As etiquetas ( Labels ) em um formulário irão ocupar menos memória se colocadas em um Control Array ao invés de usarmos dez controles individuais.
  2. Use o controle Frame ao invés do controle Picture como container para outros controles.
  3. Para tratar imagens prefira usar, quando possível o controle Image ao invés do controle Picture.
  4. Defina , quando possível , a propriedade AutoRedraw para False e a popriedade ClipControls para False.
  5. Destrua os formulários e coleções atribuindo a eles a declaração Nothing
  6. Em operações matemáticas procure usar variáveis Integer. Na divisão use o sinal ( \ ) ao invés de ( / ) . Além disso utilize .05 ao invés de 1/2 . Ex: 11 * .5 =  5.5 é mais rápido que  11/2 = 5.5
  7. Utilize a cláusula With para operações referenciando uma longa lista objetos.
  8. Para mover controles use o comando Move ao invés de definir as propriedades Top e Left.
  9. Utilize DoEvents para permitir que o usuário possa realizar outra operação enquanto o seu processamento ocorre em segundo plano. Isto dá a sensação ao usuário que as coisas não estão "paradas"...
  10. Nada mais irritante para o usuário do que ver a ampulheta ficar solitária na tela a rodar e rodar. Se o processamento a realizar requer um tempo maior utilize uma barra de progresso ou uma mensagem dinâmica para dar ao usuário uma idéia de quanto já foi feito e quanto ainda falta...

O acesso a dados : SQL um caminho mais rápido...

Quando o assunto é acesso a banco de dados a questão desempenho pode ser uma questão de vida o morte ( de sua aplicação é claro ). É claro que muitos fatores podem fazer a diferença , a começar pela base de dados a qual deseja acessar: SQL Server , Access ,  Oracle , etc... . 

O acesso aos dados é outro gargalo que você deve tratar com carinho, afinal , as atualizações envolvendo o processo de gravar / ler o banco de dados são frequentes e um código mal escrito poderá comprometer sua aplicação. Geralmente a regra para acessar qualquer base de dados quanto a que código você deverá utilizar é :  use SQL .

Usando SQL você ganha em performance , manutenção e escalabilidade sem contar que ficará muito mais fácil portar sua aplicação para acessar qualquer outro banco de dados relacional. 

A título de estudo vamos mostrar o quanto a SQL é mais rápida para selecionar dados da tabela Authors da  base de dados Access (Biblio.mdb) em comparação com o tradicional código DAO. 

Nosso estudo será sobre um projeto que terá como objetivo encontrar o nome de cada autor da tabela Authors do banco de dados Biblio.mdb que comecem com a letra  "J" com ano de nascimento superior a 1920. Vamos ao projeto e ao código:

Private dbWork As Workspace
Private dbData As Database
Private dbTabela As Recordset
Private dbTempo As Double
Private dbTabelaSQL As Recordset

Private I as Long

Private Sub Form_Load()
     
      Set dbWork = DBEngine.Workspaces(0)
      Set dbData = dbWork.OpenDatabase (App.Path & "\Biblio.mdb")
      Set dbTabela = dbData.OpenRecordset("Authors",dbOpenDynaset)
          
End Sub

Private Sub Command1_Click()

    Debug.Print "Usando Código DAO"
    'Inicio Código DAO
    dbTempo = Timer

    dbTabela.MoveLast
    dbTabela.MoveFirst
    For I = 0 To dbTabela.RecordCount - 1
        If Left$(dbTabela.Fields("[Author]"), 1) = "J" And _
        dbTabela.Fields("[Year Born]") > 1920 Then
            Debug.Print " Codigo: " & dbTabela.Fields("[Au_ID]") _
            & ",   Nome do Autor: " & dbTabela.Fields("[Author]") _
            & ",   Nascimento: " & dbTabela.Fields("[Year Born]")
        End If
        dbTabela.MoveNext
    Next I
    'Fim

    dbTabela.close

    set dbtabela=nothing
    dbTempo = (Timer - dbTempo)
    Debug.Print "Tempo gasto usando DAO : " & dbTempo

End Sub

Private Sub Command2_Click()
   
    Debug.Print "Usando SQL"
    'Inicio
    dbTempo = Timer
    Set dbTabelaSQL = dbData.OpenRecordset("SELECT * FROM " _
    & " [Authors] WHERE [Author] Like 'J*' And [Year Born] > 1920 ")

    dbTabelaSQL.MoveLast
    dbTabelaSQL.MoveFirst
    For I = 0 To dbTabelaSQL.RecordCount - 1
        Debug.Print " Código: " & dbTabelaSQL.Fields("[Au_ID]") _
        & ",   Nome do Autor: " & dbTabelaSQL.Fields("[Author]") _
        & ",   Nascimento: " & dbTabelaSQL.Fields("[Year Born]")
        dbTabelaSQL.MoveNext
    Next I
    'Fim
    dbTempo = (Timer - dbTempo)
    Debug.Print "Tempo gasto usando SQL: " & dbTempo
    dbTabelaSQL.Close

    set dbtabelaSQL =nothing

End Sub

Execute e compare. Agora ,  você decide...