KnowledgeBase Archive

An Archive of Early Microsoft KnowledgeBase Articles

View on GitHub

Q37770: "Program Memory Overflow": Break into SUBprograms

Article: Q37770
Product(s): See article
Version(s): 6.00 6.00b 7.00 7.10 | 6.00 6.00b 7.00 7.10
Operating System(s): MS-DOS | OS/2
Keyword(s): ENDUSER | SR# G881028-5376 B_QuickBas | mspl13_basic
Last Modified: 10-AUG-1990

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:

      x=20
      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:

      X$="test.dat"
      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.

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.

Copyright Microsoft Corporation 1986-2002.