VBShop
Visual Basic tips
Optimize!
What's new?
VB surveys
Download files
This page includes some tips on
If you need more tips, check some VB Books!
Optimizing for memory
Get rid of dead code
Unused code increases EXE size. It also slows down your program, and makes it difficult to understand.
- An old project may have tens of subs and functions that are not needed any more
- If your projects share some modules, they don't usually use all of the procedures.
- VB 3.0 defines dozens of constants CONSTANT.TXT and DATACONS.TXT. You will not need all of these. - Newer versions of VB have these constants built-in.
Project Analyzer helps you to find all dead code.
Type your variables
VB's default data type is Variant. Avoid Variants when possible.
They are slow, and they consume memory.
- If you use Variant instead of, say, Integer you waste 14 bytes of memory.
This can be significant in a large project.
- Integers are much faster than Variants. This is true
particularly in For..Next loops.
Use Option Explicit to force declaration of your variables. This helps you to
get rid of unnecessary Variants.
Project Analyzer helps you to find missing Option Explicits and implicit Variants.
Avoid fixed-length Strings
Fixed-length strings occupy more memory than variable-length ones.
The problem is worse if you have to reserve lots of space for long strings
in your fixed-length String variables.
Avoid static variables
Static variables are those that reside in the memory for the whole execution time.
The opposite of static variables are dynamic variables. Dynamic variables
are procedure-level variables that are created when the procedure is entered, and
destroyed when the procedure ends.
Use the following table to determine whether your variables and arrays are
static or dynamic.
|
Variables |
Arrays |
Static |
- Variables you declare in the (declarations) section
- Variables you declare inside a procedure with the
Static keyword
|
- Arrays you declare with subscripts in the (declarations) section, like this:
Dim MyArray(45, 65) As Integer
- Arrays you declare inside a procedure with the
Static keyword
|
Dynamic |
- Variables you declare inside a procedure
|
- Arrays you declare without subscripts in the (declarations) section, like this:
Dim MyArray() As Integer
- Arrays you declare inside a procedure with the
Dim or ReDim keyword
|
Reclaim memory after use
If you are using static variables, it's important to reclaim
the memory they occupied when you don't need the variables
any more. With dynamic variables memory isn't so much of a problem,
because they are destroyed when the procedure ends.
The below table shows how you can reclaim the memory occupied by different
variable types. Arrays are discussed below the table.
Type of variable |
Code to reclaim occupied space |
Variable-length String | MyString = "" |
Variant | MyVariant = Empty |
Form | Unload MyForm |
Object | Set MyObjectVariable = Nothing |
Arrays
Arrays are often memory-hungry. This applies especially to static arrays,
whose size is fixed for the lifetime of the program. Dynamic arrays are better
for memory optimizations, because they can be resized. However, some memory optimization
can be applied to both array types.
One way to reclaim space occupied
by an array is to clear all its elements one by one as shown
above. Another way is to use Erase
or ReDim
.
-
Erase
frees the memory used by dynamic arrays. With static arrays, however, the effect is somewhat limited. Doing Erase
for a static array is the same as clearing all its elements separately.
-
ReDim
can be used only for dynamic arrays. You can ReDim
a dynamic array to a smaller size. If you just want to reduce the array and still preserve some data in it, you can use ReDim Preserve
, like this:
ReDim Preserve MyArray(SmallerSize)
Some graphics optimizations
- Reclaim graphics memory with
LoadPicture()
and Cls
.
You can also set the Picture
property to Nothing
(VB 4.0 and later).
- Use Image controls instead of PictureBoxes.
- Use RLE, GIF, JPG, and WMF picture formats instead
of BMPs. If possible, try to reduce the number of colours in your pictures.
- Load a picture only once. If you need to display one picture
in several places, you can just assign it from one control
to another, like this:
MyGraph.Picture = OldGraph.Picture
- Set
AutoRedraw = False
. If it's True
, VB will
create an AutoRedraw image that consumes memory.
Optimizing for speed
Some memory optimizations described in the previous chapter contribute to
speed optimization too. These are getting rid of dead code and using
appropriate variable types instead of Variants. On many occasions, when you minimize
memory usage you will also minimize execution time. In some cases, however, the
two goals may be contradictory.
Now some ways to make faster code.
Cache properties in variables
If you are going to need the value of a property more than once, assign it to a variable.
Variables are generally 10 to 20 times faster than properties of the same type.
Use For Each..Next
instead of For(index)..Next
Collections allow you to iterate through them using an integer For(index)..Next
loop. However, For Each..Next
is often faster. Besides, it's easier to read too!
Check for loops
Normally, loops are those parts of a program that take the most time to execute. The worst thing is several loops nested.
Mathematical complexity
You may have heard of mathematical complexity measures like O(n) and O(n2).
O(n) means that the execution time of a procedure is proportional to the input size n. O(n2) means it's proportional to the square of the input size. In other words, O(n) is much faster than O(n2), if n is large.
The worst case is denoted by O(2n). This means that execution time rises exponentially when n increases. On the other hand, if execution time rises only logarithmically, like O(log n), you have a fast
procedure even for large sets of data.
Very briefly, you calculate mathematical complexity like this:
Code example | Complexity |
Sub FastProcedure(n)
For i = 1 to n
Debug.Print "Hello, world!"
Next
End Sub |
O(n) |
Sub SlowProcedure(n)
For i = 1 to n
For j = 1 to n
Debug.Print "Hello, world!"
Next
Next
End Sub |
O(n2) |
Sub SlowestProcedure(n)
For i = 1 to n
SlowProcedure i
Next
End Sub |
O(n3) |
Mathematical complexity (and the time to execute) is mostly due to the number of nested loops. With a recursive procedure (procedure that calls itself), the problem isn't that simple, but most of VB procedures are not recursive.
Project Analyzer detects nested loops, which is a very rough estimate of mathematical complexity.
Working with objects
Minimize the dots. Each dot consumes some time, and makes the code more difficult to read.
You can refer to an object's default property just with the name of the object (without the name of the property!).
You can also assign an object to an object
variable, like this:
Dim X As SomeObject
Set X = SomeContainer.SomeObject(123)
Now you can refer to X
instead of the long expression SomeContainer.SomeObject(123)
. In VB 4.0 and later you can use
With..End With
for the same effect.
Use early binding. If you know what the type of an object will be, declare your
variables with that type. Avoid variables of the general type Object
as long as you can. Use the specific type instead.
Optimize display speed
Often it's important how fast your application appears to run, even
if the the actual speed isn't that high. Some ways to speed up display speed:
- Set ClipControls property to False.
- Use Image instead of PictureBox, and Label instead of TextBox, if possible.
- Hide controls when setting properties. This prohibits multiple repaints.
- Keep a form hidded but loaded if you need to display it fast.
The drawback of this method is that it consumes some memory.
- Use background processing for longer runs. You can achieve background processing
with appropriately placed
DoEvents
. A good place to put DoEvents
is inside time-consuming loops. This needs some consideration, because the user might click some buttons, for example, and your program must know what
the user is allowed to do when the background process is running.
Set flags like Processing=True and check them in appropriate places.
- Use progress indicators.
- Pre-load data you will need later. For example, you can load the contents of
a database table into an array for faster access.
- Use Show in Form_Load event.
- Simplify your startup form, or use a splash screen.
How to make understandable code?
A few guidelines:
- Use descriptive module, procedure, variable, constant and control names. Longer names tend to be more descriptive.
- Use constants instead of numeric values and string literals. Like this:
Global Const APPNAME = "My Fancy Program v1.0"
Global Const MAX_SIZE = 32767
- Comment every procedure, module and the interface to them. A good practice is to put a few comments just after the procedure name, like this:
Function FileAge(ByVal Filename As String) As Long
' Detects how old the file Filename is.
' Returns the age of the file in days, -1 in the case an error occurs.
' Includes error handling.
- Document the structure of your project - which module does what,
and which modules call which one.
- And the usual advice: Don't use
Goto
! There is nothing you can't do with If
and Do..Loop
. The only exception is On Error Goto
.
Project Analyzer generates extensive project documentation with your comments included. It also measures the length of names.
Split complex procedures
Overly long and complex procedures are hard to understand. They are error-prone. One particular sign of a complex procedure is the amount of nested conditionals
(if, do..loop, select case
).
Project Analyzer detects complex procedures in a number of ways.
Use ByVal parameters
By default, all parameters to a VB procedure are passed by reference. Consider, for example, the following piece of code:
Function MultiplyByTwo(x As Integer) As Integer
x = x * 2
MultiplyByTwo = x
End Function
...
MyNumber = 7
Debug.Print MultiplyByTwo(MyNumber)
How much is MyNumber after a call to MultiplyByTwo? It's 14, although one would easily think it's still 7!
This is because MultiplyByTwo doubles the value of parameter x before returning it back, and the change reflects in MyNumber. In fact, passing parameters by reference means that MyNumber and x are the same variable!
The solution to this is easy. Pass the parameter by value using ByVal
, like this:
Function MultiplyByTwo(ByVal x As Integer) As Integer
Now, even if MultiplyByTwo changes the value of x, it will never change the value of MyNumber in the calling procedure.
If you really want to use by reference passing, use it explicitly like this:
Function MultiplyByTwo(ByRef x As Integer) As Integer
Use Private
Whenever possible, use the keyword Private
. This will make your procedures and variables accessible inside the module only. The advantage is increased modularity in your code.
Private MyVariable As Integer
Private Sub MyProcedure()
Project Analyzer detects variables, constants and procedures that could be declared Private.
How to make robust code?
Use error handlers
VB crashes easily. This is especially nasty with database programming - Access databases often get corrupted. A fast way to prevent crashing is to use On Error Resume Next
.
A still better way is to implement real error handlers. You could try VB/Rig to automatically insert error handlers in your code. It's shareware by Brad Kaenel.
Test with database locking
A common reason for database applications to behave strangely is locking. In a multiuser environment, a database table cannot always be opened, because another user is using it.
To tackle this problem, design error handlers carefully. To test them, you may use DB Lock.
How to develop more efficiently?
Reuse, reuse, reuse!
Reusability is the magic word of programming today. In VB, you can reuse procedures, code modules, or class modules. Reuse greatly reduces the time to develop a program.
You can achieve reusability if you program in an object oriented language creating reusable classes. Although VB isn't a strictly object oriented language, it has a simple class mechanism called class modules (.cls). Visual Basic 5.0 also creates ActiveX objects, that
are quite a powerful mechanism for reuse.
Project Analyzer measures reusability in 2 ways:
- It shows the number of procedures that call a procedure. The larger the number,
the more reusable your probably procedure is.
- An extension to Project Analyzer, called Super Project Analyzer, even calculates cross-project reuse ratios.
Some interesting survey results
Problems experienced by VB users.
Other programming languages used by VB programmers.
The tips were collected by Tuomas Salste,
a BASIC programmer since 1985, and a Visual Basic programmer since 1993.
VBShop
vbshop@aivosto.com