Microsoft KB Archive/37770

From BetaArchive Wiki
Knowledge Base

"Program Memory Overflow": Break into SUBprograms

Article ID: 37770

Article Last Modified on 11/21/2006


  • Microsoft QuickBasic 4.0
  • Microsoft QuickBASIC 4.0b
  • Microsoft QuickBasic 4.5 for MS-DOS
  • Microsoft BASIC Compiler 6.0
  • Microsoft BASIC Compiler 6.0b
  • Microsoft BASIC Professional Development System 7.0
  • Microsoft BASIC Professional Development System 7.1

This article was previously published under Q37770


The code generated by BC.EXE in Microsoft Basic Compiler versions 6.00 and 6.00b, Microsoft Basic Professional Development System (PDS) versions 7.00 and 7.10, and QuickBasic versions 4.00, 4.00b, and 4.50 may be larger (on disk or in run-time memory) than that compiled with previous versions. With the increase in product features, the program size has grown. Therefore, it is possible that your program will no longer compile and will give a "Program Memory Overflow" error. This error can be avoided by breaking the program into smaller, separately compiled subprograms or FUNCTION procedures.


At compile time, the BC.EXE compiler options can make a big difference in object file size. The /D (debug), /E (error handling with RESUME label), and /V (event handling between statements) compiler options generate the largest amount of code. The /X (error handling with RESUME NEXT, RESUME, and RESUME 0) and /W (event handling between lines) options generate less code than /E and /V; however, /X and /W still generate a fair amount of code.

If you find that even with a careful choice of compiler options the program is still too big to compile, the program should be broken up into smaller modules that can be linked together.

Each module can contain up to 64K in code and share a 64K data segment with the other modules. For code to be placed into its own module, it must be a subprogram or FUNCTION procedure. A subprogram procedure is surrounded by the SUB and END SUB statements. A FUNCTION procedure is surrounded by the FUNCTION and END FUNCTION statements. For more information about the memory the compiler uses and how to determine segment sizes for code and data, query in this Knowledge Base for the following words:

determining and segment and sizes and LINK and /Map

Also, if a program works in the QuickBasic environment, BC.EXE usually compiles it to an executable program. However, there are two exceptions. If the program contains a large $INCLUDE file with RESUME and RESUME NEXT in it, the BC.EXE compiler may fail. The BC.EXE compiler builds a table of line numbers for RESUME/RESUME NEXT statements at 4 bytes each so it can tell where to resume back to. This adds additional code to the program and causes memory depletion. The QB.EXE interpreter does not have to keep the table, so less code is generated.

To work around this situation, you can do the following two things:

  1. Use RESUME <label> instead of RESUME NEXT. Note that RESUME <label> should only be used to return to the same procedure level as where the error occurred, or else stack space will be consumed without being released, which can result in an "Out of stack space" error. For example, if an error occurs in a SUB procedure that is handled by an error handler in the main level code that performs RESUME <label> to a label in the main level code, then return addresses for the SUB remain unused on the stack and unavailable to the program.
  2. Break the program into smaller separate modules.

If you have a large number of static numeric arrays, the BC.EXE compiler can run out of memory. In the QuickBasic QB.EXE or QBX.EXE environment, static numeric arrays are not stored in the DGROUP data segment; they are stored in an additional segment. When the program is compiled with BC.EXE, these arrays are placed into the DGROUP data segment. This segment is limited to 64K. One way to work around this segment limitation is to make the static arrays dynamic to put them in the far heap.

Dynamic non-variable-length-string arrays are stored on the far heap and not in the DGROUP data segment. There are three different ways to make an array dynamic, as follows:

  1. Use the REM $DYNAMIC metacommand to make all arrays dynamic.
  2. Use a variable as the number of elements in the DIM statement, as in the following example:

          DIM array(x)
  3. Place the array in COMMON and dimension the array after the COMMON statement:

          COMMON SHARED array()
          DIM array(100)

Once the program compiles, there are a few things that can be done to reduce the size of the linked executable file. The following is a list of ways to help reduce the size of .EXE files:

  1. Use the /E (/EXEPACK) linker option. This linker option removes sequences of repeated bytes and optimizes the load-time relocation table. The result is that executable files linked with this option may be smaller and may load faster than files linked without this option. Note: The /EXEPACK option cannot be used with the /Q option.
  2. For stand-alone .EXE files (that is, those compiled with the BC /O option) that use a string variable for the filename in the OPEN statement, linking in the file NOCOM.OBJ reduces the size of the programs by about 4K. (NOCOM.OBJ should be used only if your program contains no OPEN "COM" statements.) For example, the following is a program that NOCOM.OBJ will help make smaller:

          OPEN X$ FOR OUTPUT AS #1

In addition to NOCOM.OBJ, Basic compiler version 6.00 provides other NOxxx.OBJ files, including NOCGA.OBJ, NOEGA.OBJ, NOGRAPH.OBJ, NOHERC.OBJ, NOLPT.OBJ, NOVGA.OBJ, and SMALLERR.OBJ. These files are discussed in both the "Microsoft Basic Compiler 6.0: User's Guide" and the README.DOC found on Disk 1. These NOxxx.OBJ files can also be used when a custom run-time module is built with the BUILDRTM.EXE utility.

For more information about stub files and optimizing code for size and speed, see Chapter 15, "Optimizing Program Size and Speed," in the "Microsoft Basic 7.0: Programmer's Guide" for versions 7.00 and 7.10.

Additional query words: QuickBas BasicCom

Keywords: KB37770