Professional Documents
Culture Documents
In an ideal world, every user of your applications would have a computer with the fastest
possible processor, plenty of memory, unlimited drive space, and a blazingly fast network
connection. Reality dictates that for most users, the actual performance of an application
will be constrained by one or more of the above factors. As you create larger and more
sophisticated applications, the amount of memory the applications consume and the speed
with which they execute become more significant. You may decide you need to optimize
your application by making it smaller and by speeding calculations and displays.
As you design and code your application, there are various techniques that can be used to
optimize the performance. Some techniques can help to make your application faster;
others can help to make it smaller. In this chapter you will learn some of the more
common optimization tricks that you can use in your own applications.
Visual Basic shares most of its language features with Visual Basic for Applications,
which is included in Microsoft Office and many other applications. Visual Basic,
Scripting Edition (VBScript), a language for Internet scripting, is also a subset of the
Visual Basic language. If you’re also developing in Visual Basic for Applications or
VBScript, you’ll probably want to share some of your code between these languages.
This chapter discusses the differences between the three versions of the Visual Basic
language and provides some tips for creating portable code.
Topics
Understanding Optimization
An introduction to optimization.
Optimizing for Speed
Techniques for making your application more efficient.
Optimizing for Size
Techniques for reducing the size of your application in memory
and on disk.
Optimizing Objects
Techniques for optimizing the use of objects in your
application.
Compiled vs. Interpreted Applications
A discussion of the pros and cons of native-code executables.
Compatibility with Other Microsoft Applications
Understanding Optimization
Optimization could be thought of as both a science and an art. The science is the
techniques of optimization; the art is determining where and when optimizations should
be applied. By definition, optimization is "the process of producing more efficient
(smaller and/or faster) programs through selection and design of data structures,
algorithms, and instruction sequences."
It is a common misconception that optimization is process that takes place at the end of
the development cycle. To create a truly optimized application, you must be optimizing it
while you are developing it. You choose your algorithms carefully, weighing speed
against size and other constraints; you form hypotheses about what parts of your
application will be fast or slow, large or compact; and you test those hypotheses as you
go.
The first step in the process of optimization is determining your goal. You can optimize
your program for many different characteristics:
• Real speed (how fast your application actually calculates or performs other
operations).
• Perceived speed (how fast your application appears to run; this is often related to
display speed but not always to real speed).
• Size in memory.
• Size of graphics (this directly affects size in memory, but often has additional
ramifications when working in Microsoft Windows).
Rarely, however, can you optimize for multiple characteristics. Typically, an approach
that optimizes size compromises on speed; likewise, an application that is optimized for
speed is often larger than its slower counterpart. For this reason, recommended
optimization techniques in one area may directly contradict suggestions in another.
It’s important to note that optimization is not always completely beneficial. Sometimes
the changes you make to speed up or trim down your application result in code that is
harder to maintain or debug. Some optimization techniques contradict structured coding
Unless you're doing tasks like generating fractals, your applications are unlikely to be
limited by the actual processing speed of your code. Typically other factors — such as
video speed, network delays, or disk activities — are the limiting factor in your
applications. For example, when a form is slow to load, the cause might be the number of
controls and graphics on the form rather than slow code in the Form_Load event.
However, you may find points in your program where the speed of your code is the
gating factor, especially for procedures that are called frequently. When that's the case,
there are several techniques you can use to increase the real speed of your applications:
• Avoid using Variant variables.
Even if you’re not optimizing your code for speed, it helps to be aware of these
techniques and their underlying principles. If you get in the habit of choosing more
efficient algorithms as you code, the incremental gains can add up to a noticeable overall
improvement in speed.
• Avoid using Before and After arguments when adding objects to a collection.
• Use keyed collections rather than arrays for groups of objects of the same type.
Collections allow you to iterate through them using an integer For...Next loop. However,
the For Each...Next construct is more readable and in many cases faster. The For
Each...Next iteration is implemented by the creator of the collection, so the actual speed
will vary from one collection object to the next. However, For Each...Next will rarely be
slower than For...Next because the simplest implementation is a linear For...Next style
iteration. In some cases the implementor may use a more sophisticated implementation
than linear iteration, so For Each...Next can be much faster.
It is quicker to add objects to a collection if you don't use the Before and After
arguments. Those arguments require Visual Basic to find another object in the collection
before it can add the new object.
When you have a group of objects of the same type, you can usually choose to manage
them in a collection or an array (if they are of differing types, a collection is your only
choice). From a speed standpoint, which approach you should choose depends on how
you plan to access the objects. If you can associate a unique key with each object, then a
collection is the fastest choice. Using a key to retrieve an object from a collection is faster
than traversing an array sequentially. However, if you do not have keys and therefore will
always have to traverse the objects, an array is the better choice. Arrays are faster to
traverse sequentially than collections.
For small numbers of objects, arrays use less memory and can often be searched more
quickly. The actual number where collections become more efficient than arrays is
around 100 objects; however, this can vary depending on processor speed and available
memory.
Often the subjective speed of your application has little to do with how quickly it actually
executes its code. To the user, an application that starts up rapidly, repaints quickly, and
provides continuous feedback feels "snappier" than an application that just "hangs up"
while it churns through its work. You can use a variety of techniques to give your
application that "snap":
• Keep forms hidden but loaded.
• Preload data.
Preload Data
You can also improve the apparent speed of your application by prefetching data. For
example, if you need to go to disk to load the first of several files, why not load as many
of them as you can? Unless the files are extremely small, the user is going to see a delay
anyway. The incremental time spent loading the additional files will probably go
unnoticed, and you won't have to delay the user again.
• Run a small Visual Basic application at startup to preload the run-time DLLs.
Determining the best algorithm for a given situation isn’t always obvious. Sometimes
you’ll want to test your hypotheses; this can be easily done by creating a simple
application to measure performance, as shown below. The Optimize.vbp sample
application also contains examples of several different test scenarios.
21. Run the application and monitor the results in the Immediate window.
This example uses the default property of Visual Basic’s Timer class to time the
execution of the procedure within the loop. By placing your code inside the loop for each
command button, you can quickly compare the performance of two algorithms. The code
can be within the loop or can be a call to other procedures.
You may need to experiment with different values for the upper bounds of the loop
counter, especially for fast routines. Make sure that you run each version several times to
get an average; results can vary from one run to the next.
You can also optimize your application by increasing data access speed.
In the past, available memory and system resources were often limiting factors in
designing an application. With 32-bit operating systems, such as Windows 95/98 and
Windows NT, these factors are rarely a concern for most Visual Basic programmers.
However, there are a number of scenarios where minimizing the size of an application is
still important.
Size is extremely important for applications that will be downloaded from the Internet or
transferred as attachments to e-mail. For those not fortunate enough to have high-speed
data connections, transferring a 1-megabyte file could take an hour or more. In addition
to the .exe file, many applications will require additional .dll or .ocx files, adding to the
size (and time) of the download. In these scenarios, you would want to optimize your
application’s size on disk.
Even if users won’t be downloading your application, it’s usually a good idea to make
your application as compact as possible. Smaller applications load faster, and because
they consume less memory, you can run additional applications at the same time. You
can often improve performance by optimizing your application’s size in memory.
To learn more about size optimizations, see the following topics:
• Reducing Code Size Tips for creating compact optimized code.
When reducing the size of an application is important, there are a number of techniques
that you can apply to make your code more compact. In addition to reducing the
application’s size in memory, most of these optimizations will also reduce the size of the
.exe file. As an additional benefit, a smaller application will load faster.
Most size optimization techniques involve eliminating unnecessary elements from your
code. Visual Basic automatically eliminates certain elements when you compile your
application. There is no reason to restrict the length or number of the following elements:
• Comments
• Blank lines
None of these elements affect the size of your application in memory when it is running
as an .exe file.
Other elements, such as variables, forms, and procedures, do take up space in memory. It
is usually best to streamline these. There are several techniques you can use to reduce the
memory your application occupies when it is running as an .exe file. These techniques
can reduce code size:
• Reduce the number of loaded forms.
• Keep data in disk files or resources and load only when needed.
For More Information To learn more about control arrays, see "Working with Control
Arrays" in "Using Visual Basic’s Standard Controls."
For More Information For information on adding resources to your application, see
"Resource Files" in "Advanced Programming Features."
If you don’t explicitly set an object reference to Nothing, a reference to the object will
remain in memory until the application is terminated; for an application that uses a lot of
objects this can quickly consume your available memory and slow the application.
You can also reclaim space by unloading forms and setting them to Nothing rather than
simply hiding them when they are no longer needed.
Debug.Print statements with strings or variables as arguments are not compiled when you
create an .exe. However, where Debug.Print statements have a function call as an
argument, the Debug.Print statement itself is ignored by the compiler, but the function
call is compiled. Then, when the application is run, the function is called but the return is
ignored. Because functions that appear as arguments to Debug.Print will take up space
and cycle time in an .exe, it may be beneficial to delete these statements before you make
an .exe.
Use the Find command on the Edit menu to search for references to a particular variable.
Or, if you have Option Explicit statements in each of your modules, you can quickly
discover if a variable is used in your application by removing or commenting out its
declaration and running the application. If the variable is used, Visual Basic will generate
an error. If you don’t see an error, the variable was not used.
For More Information To learn more about the Debug.Print statement, see "Printing
Information in the Immediate Window" in "Debugging Your Code and Handling Errors."
You can also use .gif and .jpg formats. They are generally much smaller; however there is
some tradeoff in image quality and loading speed.
Visual Basic enables you to think about the architecture of your application in new ways.
Instead of a single, monolithic executable, you can write an application that consists of a
core front-end executable supported by a number of ActiveX components. This approach
offers several significant optimization benefits:
• The components are loaded on demand and can be unloaded when no longer
needed.
• Remote components can use the resources of other machines on the network.
• In-process
• Remote
These three kinds are not exclusive: You could use all three in a single application. But
from the standpoint of optimizing your application, they each have very different
characteristics.
Cross-Process Components
A cross-process component is an executable program that offers its services to other
programs. Like all executables, it starts up and runs with its own stack in its own process
space; thus, when a application acting as a client uses one of the objects provided by a
component, the operation crosses from the client's process space to the component's —
hence the name. Cross-process components offer some valuable features when compared
to the other types:
• Untrapped errors in the component won't cause the calling application to crash.
In-Process Components
• No cross-process overhead
Remote Components
The Enterprise Edition of Visual Basic enables you to create remote components that
execute on a separate machine elsewhere on the network. Although network overhead
will inevitably exact a toll on application performance, you can make up for it by using
the resources of additional CPUs. This is particularly true when you work with a remote
component that is operating on data that is local to the machine containing the
component. Since this data would have to be fetched across the network anyway, a
component operating on it locally and returning only the results across the network can
actually be more efficient.
For example, you might write an object in a component that can search for files matching
a specified criteria on the local hard disk. By making this a remote component and
placing a copy on each machine on the network, you could write a distributed file-finder
program that searches all the network components in parallel, using all those CPU
resources.
Optimizing Objects
As you use more and more objects in your Visual Basic applications, optimizing your use
of those objects becomes more and more important. There are several key techniques to
making the most efficient use of objects:
• Use early binding.
• For many programs, especially those doing a lot of Windows API calls, COM
method calls, and string manipulations, native code will not be much faster than
p-code.
• Applications that consist primarily of functions from the Visual Basic for
Applications run-time library are not going to see much if any advantage from
• Code that involves a lot of subroutine calls relative to inline procedures is also
unlikely to appear much faster with native code. This is because all the work of
setting up stack frames, initializing variables, and cleaning up on exit takes the
same time with both the p-code engine and generated native code.
Note that any calls to objects, DLLs or Visual Basic for Applications run-time functions
will negate the performance benefits of native code. This is because relatively little time
is spent executing code — the majority of time (usually around 90–95%) is spent inside
forms, data objects, Windows .dlls, or the Visual Basic for Applications run time,
including intrinsic string and variant handling.
In real-world tests, client applications typically spent about 5% of their total execution
time executing the p-code. Hence, if native code was instantaneous, using native code for
these programs would provide at most a 5% performance improvement.
What native code does is to enable programmers to write snippets of code or
computationally intensive algorithms in Basic that were never possible before because of
performance issues. Enabling these "snippets" to run much faster can also improve the
responsiveness of certain portions of an application, which improves the perceived
performance of the overall application.
For More Information To learn more about native-code compilation, see "Compiling
Your Project to Native Code" in "More About Programming."
Visual Basic is the senior member of the family of Visual Basic products that includes
Visual Basic for Applications and Visual Basic, Scripting Edition (VBScript). While
most of the code that you write in Visual Basic can be shared with applications written in
Visual Basic for Applications or VBScript, there are some exceptions.
Elements specific to Visual Basic, such as forms and intrinsic controls, are contained in
the type library Vb6.olb (which is also visible in the Object Browser). In general, code
written in Visual Basic is portable to Visual Basic for Applications as long as it doesn’t
reference these elements.
For More Information To learn more about Visual Basic for Applications, visit the
Microsoft Web site at http://www.microsoft.com.To learn more about referencing
objects, see "Creating a Reference to an Object" in "Programming with Components." To
learn more about native-code compilation, see "Compiling Your Project to Native Code"
in "More About Programming."
If you have the Professional or Enterprise edition of Visual Basic, you can compile your
code either in standard Visual Basic p-code format or in native code format. Native code
compilation provides several options for optimizing and debugging that aren't available
with p-code.
Note All projects created with Visual Basic use the services of the run-time DLL
(MSVBVM60.DLL). Among the services provided by this DLL are startup and shutdown
code for your application, functionality for forms and intrinsic controls, and run-time
functions like Format and CLng.
Compiling a project with the Native Code option means that the code you write will be
fully compiled to the native instructions of the processor chip, instead of being compiled
to p-code. This will greatly speed up loops and mathematical calculations, and may
somewhat speed up calls to the services provided by MSVBVM60.DLL. However, it
does not eliminate the need for the DLL.
To compile a project to native code
1. In the Project window, select the project you want to compile.
Figure 8.6 The Compile tab in the Project Properties dialog box
6. From the File menu, choose Make Exe, or Make Project Group.
The following table describes the native code options for optimization.
Option Description
Assume No Aliasing (Advanced Tells the compiler that your program does not
Optimization) use aliasing. Checking this option allows the
compiler to apply optimization such as storing
variables in registers and performing loop
optimizations.
Create Symbolic Debug Info Produces a .pdb file and .exe or .dll file
containing information to allow for debugging
using Microsoft Visual C++ 5.0 or another
compatible debugger.
Favor Pentium Pro(tm) Optimizes code to favor the Pentium Pro(tm)
processor.
No Optimization Disables all optimizations.
Optimize for Fast Code Maximizes the speed of .exe and .dll files by
telling the compiler to favor speed over size.
Optimize for Small Code Minimizes the size of .exe and .dll files by
telling the compiler to favor size over speed.
Remove Array Bounds Checks Disables Visual Basic array bounds checking.
(Advanced Optimization)
Remove Floating Point Error Checks Disables Visual Basic floating-point error
(Advanced Optimization) checking.
Remove Integer Overflow Checks Disables Visual Basic integer overflow
(Advanced Optimization) checking.
Remove Safe Pentium(tm) FDIV Disables checking for safe Pentium(tm)
Checks (Advanced Optimization) processor floating-point division.
PERFORMANCE
There are many ways to speed up a Visual Basic program. Unfortunately most produce
only a small benefit. Even if a program uses huge collections, converting them into arrays
will probably only save you a few percent in run time. On the other hand, rewriting the
program's main algorithms can reduce the run time by factors of hundreds. Here is a list
For example:
If a * a + b * b = 4 Then
... is much faster than
If Sqr(a * a + b * b) = 2 Then
Sent me this important technique. I have used this one, too, and it can make an
enormous difference, depending on your application. If you have to do anything with
repetative calculations really fast (ie: Circles or anything dealing with Trig functions), it
may help out a lot to create a table of values for whatever resolution you need for the
data. For example, precalculating the x, y coordinates of a circle about a point every two
degrees (or use radians, which are actually better for this) is often good enough and much
faster than using the SIN, COS and TAN functions. Rewrite the program in C++ or
Delphi. (This is rarely an option, but it is the ultimate solution when you REALLY need
more performance, so I am listing it anyway.) Upgrade to Visual Basic 5 or 6. Compiled
native Visual Basic executables are a lot slower than C++ or Delphi executables, but they
are much faster then the non-compiled programs produced by Visual Basic 4 and earlier
versions. (This is another expensive option, but easier than learning a new language.)
Profile your application. Use a performance monitoring tool to see exactly where the
program is spending most of its time. Visual Basic 4 and 5 come with one. Visual Basic 6
does if you buy the enterprise edition.
Don't waste your time optimizing code that is already fast enough.
Decompress graphics. Set the Picture property for a Form or PictureBox to a .bmp file,
not a compressed JPEG or GIF file. Those files are stored in the program in compressed
form so the program needs extra time to display them.
Preload forms. Load all the forms you will use when the program starts.
Then they can display faster when you need them.
Use arrays instead of collections. Arrays are much faster.
Use collections only if you need their special features like keyed lookup.
Preallocate arrays so they are big enough and you don't have to ReDim them later.
If you need to set all entries in an array to zero, use ReDim to reallocate it.
This takes longer than leaving the array alone (the previous tip), but is faster than setting
the entries one at a time. To set entries to zero in a fixed-sized array (allocated using
Dim), use the Erase statement. This destroys dynamically allocated arrays, but resets
fixed-sized arrays. Use the MemCopy or RtlMoveMemory API functions to copy arrays
instead of copying their entries one at a time.
Use specific data types instead of Variants. Always declare a variable's data
type. If you don't, it default to variant.
Cache properties you use multiple times. If the program needs to refer to
txtLastName.Left
several times, save that value in a variable and refer to the variable instead. Accessing
variables is much faster than accessing properties.
Use Line (x1, y1)-(x2, y2), , B
to draw a box instead of using Line four times. Use Image controls instead of
PictureBoxes if possible. Image controls take less memory.
Use Frame controls to hold other controls instead of PictureBoxes. Frame controls
take less memory.
Use control arrays for controls that are unimportant. For example, many forms
contain a lot of uninteresting labels. Put them all in a control array. A control array
containing 10 controls usees less memory than 10 individual controls. Perform long,
low-prioirity calculations in the background using a Timer.
Use comments and meaningful variable names. Long comments and variable
names, and blank lines do not add to the compiled program's size so there is no harm in
using them.
Do not line number every line because line numbers increase the program's size.
Remove unused variables and code since they remain in the program and take up
memory.
Use DoEvents to allow the user to perform other actions while your long
process is running. This can reduce the user's frustration even if it doesn't make the
program move faster. (John Dye <mailto:jrdye@dialpoint.net>)
Use the FindFirstFile, FindNextFile, and FindClose API functions to quickly
search directories. Thanks to Nikolaos D. Dimopoulos <mailto:NickDD@ISM-
Solutions.com>. [Note that using API functions is often but not always faster. It is
The With command speeds things up in the same way, so this could be:
With SelectedEmployee.NextOfKin.HomeInformation.Address
.Street = txtStreet.Text
.City = txtCity.Text
.State = txtState.Text
.Phone = txtPhone.Text
End With
Use ByRef to pass values instead of ByVal. When you use ByRef, the program
passes the (small) address of the value. When you use ByVal, it must make a new copy of
the value and pass that. Generally it is faster to pass the address instead of a copy.
However, when you are making an out-of-process call, ByVal is faster. With out-of-
process calls, Visual Basic must repackage the value anyway to send it to the other
process. If you use Byref, it must then unpackage the returned result and that takes extra
time.
Use * instead of ^ to take simple integer powers.
For example, use
A=B*B
instead of
A = B ^ 2.
The first is faster.
If you need to build a long string, build it in pieces and then join the pieces
when they are all finished.
For example, suppose subroutines
AddText1, AddText2
, etc. append text to a string.
Then the following code:
Dim txt As String
[Note: For loops do not evaluate their bounds every time through the
loop. When the For statement starts, the system calculates the upper bound and saves it. It
does not recalculate it every time through the loop.
Therefore this code is reasonably fast:
For i = 1 To SlowFunction()
total = total + i
Next i Rod]