How to Optimize Memory Management in VB 3.0 for Windows

Last reviewed: October 21, 1997
Article ID: Q112860
3.00 WINDOWS kbprg kbcode

The information in this article applies to:

- Standard and Professional Editions of Microsoft Visual Basic for

  Windows, version 3.0

SUMMARY

This article outlines how various memory areas in Visual Basic are managed. It covers the following areas:

  • General Memory Management:

        - Windows Limits
        - Application Limits
        - Form Limits
        - Data Limits
        - Global Name Table
        - Global Symbol Table
        - Global Data Segment
        - Module Name Table
        - Module Symbol Table
        - Module Data Segment
        - Module Code Segment
        - System Resources
        - Stack Space
        - When Code and Resources are Loaded and Unloaded
    
  • "Out of Memory" and Related Error Messages:

        - Common Ways to Avoid "Out of Memory"
        - Common Ways to Diagnose "Out of Memory"
        - Verifying a Memory Leak
    
  • Optimization Recommendations

        - System Resource Overview
        - Visual Basic Controls: USER Resource Byte Use
        - Menu USER Resources
        - System Resource Optimizations
        - Size Optimizations
        - Speed Optimizations
    

GENERAL MEMORY MANAGEMENT

Windows Limits

Windows version 3.1 imposes a limit of 600 windows in existence at one time. All windows in all applications running in Windows count toward this limit. In Visual Basic, each form and non-graphical control (all controls except shape, line, image, and label) counts as one window.

Application Limits

  • There can be a maximum of 256 distinct objects in a project.
  • There can be a maximum of approximately 230 forms in a project, with up to 80 loaded at one time.
  • The total count of all procedures, form and code modules, and DLL declarations must be less than 5,200, not counting event procedures that are empty of code.

Form Limits

  • There can be a maximum of 470 controls on a single form, depending on control type.
  • There can be a maximum of 254 different control names per form. A control array counts as one name.
  • The data in all form properties and all control properties on a given form is stored in a single data segment limited to 64K, except for the List property of combo and list-box controls and the Text property of multiline text-box controls.

Data Limits

Specific data limits for Visual Basic version 3.0 are well documented in Appendix D of the Microsoft Visual Basic "Programmer's Guide." Please look there for information on data limits.

Global Name Table

Each application uses a single Global name table (up to 64K in size) that contains all Global names. Global names include the following:

  • The actual text of the Form or Code module name.
  • The actual text of each event procedure name appears in the Global symbol table only once. For example, two different forms each have a Form_Load event procedure, but only one entry for the event procedure is made in the Global symbol table.
  • The actual text of each non-event Sub or Function procedure name in a form module (.FRM file). Even though these Sub or Function procedures are private to the form, within the application, their names are listed globally but with a flag set to indicate that they are private to that form.
  • The actual text of each non-event Sub or Function procedure name in a code module (.BAS file). As with Sub or Function procedure names in a form module, the code module Sub and Function procedure names are listed globally but with a flag set to indicate that they are global to the application (unless the Private key word is used, in which case the flag is set to indicate that they are private to that code module).
  • The actual text for the name of each Global constant.
  • The actual text for the name of each Global variable.
  • The actual text for the name of each user-defined type definition.
  • The actual text for the name of each Global DLL Sub or Function procedure declaration.
  • Four bytes of overhead for each of the above listed Global names in the Global name table as well as approximately 100 bytes of overhead for the hash table for these Global names.

NOTE: When your project is made into an .EXE file, most of the Global name table is not needed. Visual Basic takes special provisions to ensure that only the names that are needed are included with the .EXE (such as DLL function names).

Global Symbol Table

Each application has a single Global symbol table that is up to 64K in size. This table contains descriptive information about each of the items named in the Global name table. Specifically, this table contains:

  • Type definitions: 4 bytes for the type plus 4 bytes for each element.
  • Type variables: 12 bytes.
  • Fixed-string variables: 12 bytes.
  • Object variables: 12 bytes (approximately).
  • Everything else: 10 bytes (approximately).
  • Approximately 100 bytes of overhead for the hash table within the Global symbol table.

NOTE: When your project is made into an .EXE file, the Global symbol table does not exist. It is only needed within the Visual Basic environment to create the .EXE file itself.

Global Data Segment

Each Visual Basic application receives a single data segment of up to 64K (minus overhead) to store the actual data referenced by Global variables and Global constants.

Space for Global string constant descriptors is also allocated in this data segment. However, the actual string data for the Global string constant is stored in a segment of up to 32K (minus overhead) allocated separately from dynamic memory.

A custom control (.VBX) is allocated space in the same 32K segment for any strings obtained with the Visual Basic API VBCreateHlstr. If the custom control does not deallocate this space, because it needs to reference these strings when it is unloaded or it doesn't clean up properly, the data in the segment may exceed 32K. If this occurs, Visual Basic allocates another segment to hold the excess data and links this new segment into the dynamic data segment chain.

Module Name Table

Each form and code module has a single Module name table that is up to 64K in size. The Module name table includes:

  • The actual text for the name of each module-level and local variable name.
  • The actual text for the name of each module-level DLL Sub or Function procedure declaration.
  • The actual text used for line numbers and line labels.
  • As with the Global name table, an additional four-byte overhead for each of the above listed module-level names in the Module name table as well as about 100 bytes overhead for the hash table for these module-level names.

NOTE: As with the Global name table, when your project is made into an .EXE file, most of the Module name table is not needed.

Module Symbol Table

Each form and code module has a single Module symbol table that is up to 64K in size. The module symbol table contains much of the same information as the Global symbol table, except for Type definitions.

NOTE: As with the Module symbol table, when your project is made into an .EXE files most of the Module name table is not needed.

Module Data Segment

Each form and code module has its own 64K module data segment. The contents of the module data segment include:

  • Local variables declared with the Static keyword.
  • Local variables declared within a Static Sub or Function procedure.
  • Module-level, fixed-length string variables.
  • Module-level variables other than arrays and variable-length strings.
  • Module-level constants.
  • Tracking data for arrays and variable-length strings (2-byte pointer each).
  • Tracking data for controls referenced in code for a form (2-byte pointer each).
  • Tracking data for nonstatic local variables (2-byte pointer each).

Module Code Segment

Each Sub or Function procedure in a form or code module can contain up to 64K of p-code (the internal representation of your code). The module-level declaration section of each form or code module can also contain up to 64K of p-code. If the procedure-level or module-level p-code exceeds this limit, Visual Basic generates an "Out of Memory" error message. There is no specific internal limit to the total size of an individual form or code module.

The amount of p-code in a procedure or in the Declarations section of a module is roughly equivalent to the number of ASCII text characters in the code. The Visual Basic documentation recommends that you save your forms and modules as ASCII text and that you keep the size of individual procedure-level or module-level code in your form and code modules to under 64K. However, practical experience by Visual Basic programmers has shown that it is best to keep the size of these under 45K to 50K of ASCII text.

This estimate is true only when you are in the development environment. Visual Basic does not include identifiers (procedure, variable, and object names) or comments in the .EXE files you create, so the resulting .EXE is much smaller. If you don't exceed the 64K limit on p-code in the development environment, you won't exceed it in the finished .EXE.

System Resources

The data space (heap) attached to the Windows libraries (USER.EXE and GDI.EXE) is the space allocated for system resources. The data space used by the GDI library contains graphics information regarding brushes, fonts, icons, and so on. The data space used by the USER library contains style information pertaining to windows (forms) and controls. The data space for each of these libraries is limited to 64K. The "About Program Manager" menu command displays, as a percentage, the lower of these two areas of memory. If you run out of either of these two heaps you will receive an "Out of Memory" error message.

Visual Basic uses Windows resources shared with other Windows applications, so it is important to make efficient use of these resources to avoid "Out of Memory" messages. For larger applications, you should reduce the number of forms and controls loaded at any one time. Forms should be loaded only when needed. Here are some ways to reduce the number of controls:

  • Use the Visual Basic Load and Unload statements to load forms only when needed at run time.
  • Use so called lightweight controls (labels, images, lines, and shapes in Visual Basic version 3.0) when possible. These controls are similar to other controls in that they do use system resources when they are being drawn or updated in the screen. But unlike other controls, the lightweight controls release resources back to the system when finished.
  • Replace controls such as command buttons that react to mouse events with an image control that has a picture of a control in it. This provides your application with similar functionality but uses less memory (system resources).
  • Try to replace several related controls with a single, larger control. For example, if several text boxes were placed on a form to represent the cells of a spreadsheet, you could replace these controls with a single picture control containing an image of the cells: lines drawn vertically and horizontally. Hit testing could be performed at run time from within the MouseDown event of the picture control. In other words, you could use the x and y coordinates passed to the MouseDown event to determine which "cell" was clicked (hit). The cell image on the picture control could be temporarily replaced by a real text box, positioned by using the Move method to allow for user input. In this manner, only two controls would be required to simulate input on a spreadsheet: a picture control and a text box.

Stack Space

Each Visual Basic application uses a single stack limited to 20K in size. The 20K size cannot be changed, so an "Out of Stack Space" error can easily occur if your program performs uncontrolled recursion, such as a cascading event.

Visual Basic itself uses the stack, even in a .EXE, so the practical limit is lower than 20K. A simple way to get an idea of this to make an .EXE file of a form with a single command button on it with the following code. Each Gosub takes 4 bytes of stack space, so you can then calculate how much free stack space you had when your procedure started.

   Sub Command1_Click ()
      Dim frameCount as Integer
      frameCount = 0
   Overflow_Stack:
      Me.Cls
      frameCount = frameCount + 1
      Print frameCount * 4
      GoSub Overflow_Stack
   End Sub

Procedure arguments and local variables in Sub and Function procedures take up stack space at run time. However, Global variables, module-level variables, and procedure-level variables declared with the STATIC keyword, and arguments in Sub or Function procedures that are defined with the STATIC keyword, don't take up stack space because they are allocated in the Module Data Segments of form and code modules.

When Code and Resources Are Loaded or Unloaded

When an application is executed, memory is allocated for the Global Data Segment and the appropriate data is loaded into it. This stays persistent until the application terminates.

When a form is loaded, system resources are allocated for the Form and all controls on that form. In addition, memory is allocated for the Module data segment and the appropriate data is loaded into it.

Each Visual Basic form or module consists of one or more code segments in the .EXE file. The code segments are marked LOADONCALL, MOVEABLE, and DISCARDABLE, which you can verify by using a copy of EXEHDR.EXE to dump the file header information. Thus, on first reference to the form or module, Windows loads the code associated with it. Windows is then free to discard it and demand-load it as it sees fit (for example, if you run low on memory). Unloading a form will not force the code segment out of memory, it's still present until Windows decides to discard the code segment.

Unloading a form does unload the instance of that form and all resources used by it and the controls on that form. However, when a form is unloaded, the Module Data Segment is not unloaded; it remains in memory until the application terminates. Thus, if you load a Form, change the values of some module level variables, unload the Form, and then load it again, the value you last assigned to the module level variable in the Form will still be present. To deallocate memory used by the Module data segment in the form, use the following line of code after you unload the form:

   Unload Form2
   Set Form2 = Nothing

This will clear all data in the Module code segment for the form.

"OUT OF MEMORY" AND RELATED ERROR MESSAGES

Common Ways to Avoid "Out of Memory"

Here are some tips to help you avoid the "Out of Memory" error message:

  • Read Appendix D (Specifications and Limits) of the "Programmers Guide." The discussion of the Global symbol table in the manual is enhanced by details presented below.
  • Read Chapter 11, "Optimizing Your Applications for Size and Speed," in the "Programmer's Guide." This offers a good starting place in its discussion of optimizing your applications memory requirements.
  • Keep the number of forms loaded at any given time to as few as possible. While the specifications indicate that 80 forms can be loaded into memory, in practice you will want to avoid pushing this upper limit.
  • If possible, take advantage of non-graphical ("lightweight") controls (shape, line, image, and label). These controls use less system resources as well as memory.
  • Use control arrays if possible rather than a large number of static controls of the same type.
  • Minimize the number of controls on a form. The upper limit of controls on a form is 470; however, they can use only 254 control names (making control arrays necessary). In practice, a form this heavily laden with controls would be slow in performance. Minimize the number and type of custom controls on a given form.
  • Save your forms and modules as text. See the "Module Code Segment" discussion above for details.
  • Ensure that the declaration for any API or other DLL calls you make are correct. Ensure that memory allocated by routines inside a DLL is actually deallocated when the process using it is finished.
  • Explicitly turn off timer controls when your application exits. If you do not, it is possible the parent form will not be unloaded, and the timer will continue firing.
  • Explicitly unload forms; especially when the application terminates. The End statement does not trigger the Unload event of a form. The only way to ensure that a form is actually unloaded is to issue the Unload statement. The Forms Collection is useful for being certain that all forms, loaded or not, are unloaded.

There is a special version of error #7, "Out of Memory -- Global Name Space", which can occur when the name space is filled. To deal with this error, minimize the size of the names used in event, private, and Global
Sub and Function procedures. See the "Global Name Table" discussion above
for details.

Common Ways to Diagnose "Out of Memory"

When you receive an "Out of Memory" error, there may be few limits to the lengths you will have to go to diagnose and locate the actual source of the problem. Make a backup of your project and place it in a temporary directory. Take any drastic measures on that backup copy. The following are some tips to help you narrow the focus in finding the cause of the "Out of Memory" error:

  • Remove any and all unnecessary device drivers from the CONFIG.SYS file. Is there any particular problem that seems to induce the error?
  • Remove any TSR (terminate and stay resident) programs from the AUTOEXEC.BAT file. Again, is there any particular TSR that induces the error?
  • Use Program Manager as the Windows desktop.
  • Do not run anything else in Windows that is not necessary. Check this by bringing up the task list (CTRL-ESC). Are Visual Basic and the Program Manager the only tasks running?
  • Change the Windows Video driver to standard VGA. It may be necessary to check if your display's vendor has released an update to the display driver. There may an incompatibility with your video driver and Visual Basic causing video memory to be incorrectly allocated or referenced.
  • Change any API or DLL calls you are making into comments by adding a single quotation mark as the first character on the line. This may not be conclusive, as the error can be generated as a result of the values returned by the calls, and not the calls themselves. In that case, hard code the return values, or provide some mechanism to simulate their action so you can test the code that responds to them.
  • Remove any custom controls you are using from the form.
  • Check to see whether you are legitimately low on RAM or the hard disk is almost full. 386 enhanced mode gives you more logical RAM than you have physical RAM, but only if you have the hard disk space free to allow this.

Verifying a Memory Leak

Memory leaks can occur when memory is allocated to perform a particular process but is not deallocated when the process concludes.

You can use a tool such as HeapWalker from the Windows Software Development kit or Visual C/C++. HeapWalker allows you to analyze your application's memory requirements and memory profile by seeing how many code segments from your application are in memory at any given time. WPS.EXE which ships with the Visual Basic CDK in the professional edition, can be used to determine which .DLL and .EXE files are running.

The Windows API GetFreeSpace() function scans the Global heap and returns the number of bytes of memory currently available. However, the results of function in a large application can be misleading. The best way to use this function is to create a demonstration program that tracks memory before and after a given process. It is important to minimize the scope of that process as much as possible or else the results will be inconclusive.

OPTIMIZATION RECOMMENDATIONS

Optimization techniques are generally a trade-off between size and speed. Some optimizations have multiple effects, for example, reducing size can improve speed because less memory may be needed which causes less disk swapping. Some Visual Basic speed optimizations affect system resource availability.

System Resource Overview

Under Windows 3.x system resources fall into one of two categories, USER and GDI. USER resources consist of Window and Menu handles. GDI resources consist of Device Context handles, Brushes, Pens, Regions, Fonts, and Bitmaps. USER and GDI resources are stored in the corresponding Windows internal DLL’s data segments which have a maximum size of 64K. Resource availability refers to how much of the 64K data segment is still available for new resources. A resource handle is an offset into the data segment to the resource’s internal control structure.

The Program Manager’s available resource indicator in the About Box displays the least available of the two type of resources. The biggest violator of USER resources is the creation of windows (for example, Dialog Boxes, Forms, Controls). Every window has a variable length internal control structure. The base size for a Window’s control structure is 64 bytes. Additional bytes are specified by the Window’s Class in order to support the specific functionality of the window. Standard controls in Windows and Visual Basic consume from 66 to 160 bytes. Visual Basic includes 4 graphical controls (Label, Shape, Line, and Image) which do not create Windows and hence consume ZERO USER resources.

Visual Basic Controls: USER Resource Byte Use

   Form .......... 206 | FileListBox .... 160 | PictureClip ..... 72
   MDIForm ....... 420 | Shape ............ 0 | SpinButton ...... 72
   PictureBox ..... 90 | Line ............. 0 | SSCheck ......... 72
   Label ........... 0 | Image ............ 0 | SSFrame ......... 80
   TextBox ........ 76 | Data ............ 72 | SSOption ........ 72
   Frame .......... 74 | Grid ............ 72 | SSCommand ....... 76
   CommandButton .. 66 | OLE ............ 164 | SSPanel ......... 80
   CheckBox ....... 76 | AniPushButton .. 170 | SSRibbon ........ 80
   OptionButton ... 76 | CommonDialog ... 166 |
   ComboBox ...... 136 | CrystalReport .. 166 |
   ListBox ....... 160 | Gauge ........... 80 |
   HScrollBar ..... 80 | Graph ........... 80 |
   VScrollBar ..... 80 | MhState ......... 72 |
   Timer .......... 72 | MSComm .......... 72 |
   DriveListBox .. 160 | MaskEdBox ....... 76 |
   DirListBox .... 160 | Outline ......... 82

Menu USER Resources

Menus also consume USER resources although their impact is very minimal. An application could have a total of several hundred menu options and still only increase the USER resource use by 24 bytes. There is ZERO resource use for the top level menu. USER resources are consumed and freed dynamically as menus are opened. The first level drop-down menu consumes 24 bytes. The second, third, forth, and so on consume 132 bytes each of USER resources. For example, a displayed third level menu would consume 288 bytes, 24 bytes for the first level, 132 bytes for the second level, and 132 bytes for the third level. Popup menus that can appear anywhere on the screen, usually at the mouse cursor location, also consume 132 bytes of USER resources.

System Resource Optimizations

The best way to reduce USER resources is to reduce the number of created windows at any one time. Any loaded form consumes USER resources regardless of whether it is visible:

  1. Break large forms (forms with many controls) into several smaller forms. Each of the smaller forms can be loaded and unloaded as necessary. Since only one of these forms at any given time is loaded, system resources will be used less. However, the added overhead of loading and unloading forms will most likely result in slower application performance, so there is a tradeoff.

  2. Implement control simulation. For example, a form could implement a toolbar by using 20 command buttons, consuming 1320 bytes of system resources. The toolbar can be implemented more efficiently with two image controls and one PictureClip control. The first image control contains one bitmap that looks like the entire toolbar. The PictureClip control contains one bitmap that contains the button down appearance of all buttons on the toolbar. When the user clicks on the toolbar (image control) the corresponding down picture is retrieved from the PictureClip control, placed in the second image control, and placed over the toolbar in the correct position. The second image control is hidden on the mouse up giving the appearance of button depression. This solution consumes 72 bytes of USER resources for the one PictureClip control. The image controls are graphical controls which consume zero USER resources.

    A second area of control simulation is text boxes. Applications that are data entry intensive contain many text-box controls. For example, if a form contained 64 text-box controls, they would consume 4864 bytes of USER resources. A simulation solution would use 1 text-box control and 64 label controls. When the user clicks on a label to edit it, the text box is resized and moved to the clicked label. This requires more coding to handle the one text box, tabbing, and access keys. This solution consumes 76 bytes of USER resources for the one text-box control. The label controls are graphical controls which consume zero USER resources.

  3. Consider redesigning the user interface. For example, many option buttons can be replaced by one combo box and many check boxes can be replaced with one multiselect list box. Some controls may be an overkill for the desired functionality. For example, using a picture box, when all that is needed is an image control.

Size Optimizations

The following are recommendations intended to help produce the smallest, fastest code possible. Please note that although saving two bytes here or four bytes there may not seem like a lot, just implementing recommendation 3 for null-length strings ("") globally throughout a product can provide significant size reduction! Furthermore, Visual Basic uses a scheme of aligning segments on a 256-byte boundary in the EXE, which means that if you use just one byte beyond the current 256-byte block, another 256-byte block will be allocated! So, some of these optimizations not only result in a time savings, they can also result in much smaller code!

  1. Put strings into external DLL's:

        - Doing this gives a much greater ease of converting text into
          other languages.
        - It also helps reduce the sizes of the code segments in the Visual
          Basic app.
        - It slightly slows down the initial loading of forms.
        - Strings can be stored in a String Table Resource inside the DLL.
    

  2. Reduce unnecessary code replication.

    Having the same code in multiple places will generally increase the size of the app. It also increases maintenance costs. In some cases it may be necessary to have the same code in multiple places, and such instances should be commented to indicate the need.

  3. Use Constants rather than string literals:

        - When used as a parameter, a string literal takes up a minimum of
          6 bytes, whereas a string *constant* takes 4 bytes.
        - When assigned to a string variable, a string literal takes up a
          minimum of 8 bytes versus the 4 bytes for a string constant.
        - Converting a parameter from a string literal to a string constant
          saves 4 bytes in the code segment, for every instance beyond the
          first.
        - Converting an assigned string literal to a string constant saves 2
          bytes in the first instance, and 6 bytes for every instance beyond
          the first.
    

  4. For strings that are used throughout the program and are Read Only, use Global string variables. Be cautious about this approach since the Global Symbol Table has a limit of 64k for storing variable names. It’s best to use this method for strings that are repeated a lot.

    Define the strings as Global, set them up in an Initialization module, and then use them in other modules instead of constantly recreating things like Chr$(9):

         Global TABCHR as String * 1
         Global CR as String * 1
         Global CRLF as String * 2
    

         Sub Init()
           TABCHR = Chr$(9)
         CR = Chr$(13)
         CRLF = CR + Chr$(10)
         End Sub
    

    By constantly using Chr$(9), the code is larger, and it is slower since it must re-create the character every time that code is executed.

  5. Put IF/THEN constructs on one line if possible.

    The ENDIF generally takes up 6 bytes, thus changing:

          If X=2 Then
    
             debug.print "HI"
          EndIf
    
       to:
    
          If X=2 Then debug.print "HI"
    
       This winds up saving 6 bytes to do the exact same function.
    
    

  6. Check to see whether the Visual Basic function you're using is really needed.

    Sometimes this means checking the function to see if the returned value really needs the additional work you're doing, such as:

          Trim$(Format$(123))
    

    In which case, the Trim$() is totally unnecessary. Other times, this means looking at what is being created, and seeing if it could be done at design time, such as " 0" instead of using Str$(0).

  7. Put functions that are only used one time, or are used seldom in their own modules. Visual Basic loads modules on demand and Windows will discard them if they don’t get used after a while:

        - Modules such as a Print module and an Initialization module can be
          loaded one time by the code and then discarded when no longer
          needed.
    

          -or-
    

        - If a special startup form is going to be used, the
          initialization code could be placed in that form, so the code will
          be unloaded with the form.
    

  8. Use Bit fields rather than strings.

    Not only does an integer take up less space in memory than a 16 character string, but it is much faster to do comparisons! i.e., it would be much faster, and more efficient, to check for the existence of multiple flags via:

          If (Flags And TestVal) Then ...
    

    than an associated routine which has to scan multiple characters in a string to see if any of them are a "0" or "1".

  9. Remove unnecessary value checks.

    For example:

          If  bFlagToBeTested = True Then ...
    

    can be written as:

          If  bFlagToBeTested Then ...
    

    Removing the "= True" saves 6 bytes from the module or form and is faster to execute. (Note: It also means that any non-zero value can be evaluated as "True".)

10.Do calculations manually at design time rather than asking the compiler
   to do them at run time.

    - If a data structure is only used for its size, store the size
      information in a Global constant or variable rather than keeping the
      entire structure around just to use the Len function. For example,
      use Const COMPANYREC_LEN = 505, rather than using Len(COVar). This
      avoids keeping a form-level variable around just so its length can
      be calculated!

      Or if the record sizes are being changed a great deal, then at least
      move the calculation to an initialization module, and do it only one
      time!  In this case, a 505-byte data structure was loaded into
      memory every time a form that used Company data was loaded.

    - Even numeric calculations take up both execution time and space in
      the EXE:  For example, use MinFree& = 102400& instead of MinFree& =
      1024& * 100&.

  • Move graphics from the application to a DLL.

    This reduces the size of the executable file for updates. The .EXE can be updated and distributed without the redistribution of the graphics in the DLL, assuming that the graphics have not changed.

    Speed Optimizations

    WARNING: The following methods are designed to help machines with low memory (RAM). However, these methods may make debugging harder, and make it harder to maintain and reuse code. Therefore, this tradeoff should be considered when using the following techniques.

    1. Never reference an object property more than once.

      Poor:

            if Form1.Caption = "ABCD" then
            elseif Form1.Caption = "DEFG" then
            elseif Form1.Caption = "XYZ" then
            endif
      

      Better:

            Temp$ = Form1.Caption
            if Temp$ = "ABCD" then
            elseif Temp$ = "DEFG" then
            elseif Temp$ = "XYZ" then
            endif
      

      Even Better:

            Select Case Form1.Caption
      
               Case "ABCD"
               Case "DEFG"
               Case "XYZ
            End Select
      
         Best:
      
            CONST CASE1 = "ABCD"
            CONST CASE2 = "DEFG"
            CONST CASE3 = "XYZ"
            ...
            Select Case Form1.Caption
               Case CASE1
                  Case CASE2
               Case CASE3
            End Select
      
         The last version is the best, because it uses constants for the strings
         (easier to maintain, less memory used, faster execution) and because it
         only references the variable (Form1.Caption) one time, rather than
         multiple times as the IF/ELSEIF constructs do. Using Select/Case
         statements will result in faster execution, however, it will be at the
         cost of slightly larger code.
      
      

    2. Avoid calling routines outside of the current form or module to reduce swapping problems on low-memory machines

      Calling routines in a central location is okay but this can lead to inefficiency. A routine in one module which calls a routine in a second module, which calls a third routine in yet another module, etc. means that all of those modules have to be loaded. Doing this can cause excessive hits on the Windows SwapFile. To alleviate this, make sure that as many of the subordinate routines that your routine needs are located in the same module.

    3. It is more efficient in Visual Basic to have local references to the current form's controls than it is to reference the proper form and then the control. Put subroutines or code that use controls in the form instead of a module whenever possible. For example:

      Module1

            Sub DoWork
            Form1.Text1.Text = “ABC”
            End Sub
      
         -versus-
      
         Form1
      
            Sub DoWork
            Text1 = ABC
            End Sub
      
      

    4. Make smaller modules:

      Normal Windows programmers look for segment sizes in the range of 4-8k. Since there is no easy way to determine how much space a particular module in Visual Basic is taking up, sometimes we can only guess. The best approach is to put subroutines that work together into the same module. Then try to make that module as small as possible.

    5. Use specific object types:

      - When calling a subroutine or function and passing an object,

          specify the exact object type being referenced. For example:
      

               Sub SubRtn1 (TxtBox as TextBox)
      
               -instead of-
      
               Sub SubRtn1 (TxtBox As Control)
      
        - If a subroutine is modifying a specific object, then use the exact
          control or form rather than referring to it via a parameter. This
          will cut down on the number of parameters and increase the speed of
          execution.
      
      

    6. Use Windows API functions to draw artwork or backgrounds on the form rather than using Picture boxes or Image controls. Using the Windows API will help make some of the forms draw quicker.

    REFERENCES

    • Visual Basic version 3.0 for Windows "Programmer's Guide," Appendix D, "Specifications and Limitations," pages 641-646.
    • Visual Basic version 3.0 for Windows "Programmer's Guide," Chapter 11, "Optimizing your Application for Size and Speed," pages 255-263.
    • Microsoft Windows Software Development Kit "Programmer's Reference," Volume 2, "Functions."


  • Additional reference words: 3.00 MemLeak
    KBCategory: kbprg kbcode
    KBSubcategory: PrgOptMemMgt
    Keywords : PrgOptMemMgt kbcode kbprg
    Version : 3.00
    Platform : WINDOWS


    THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

    Last reviewed: October 21, 1997
    © 1998 Microsoft Corporation. All rights reserved. Terms of Use.