home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #1 / monster.zip / monster / CLIPPER / CLIPTIPS.ZIP / BCSMEM.ZIP / MEMORY.DOC < prev    next >
Text File  |  1993-03-27  |  53KB  |  1,134 lines

  1. (10U
  2.  
  3.  
  4.                         Clipper Memory Management
  5.  
  6.                             by Roger Donnay
  7.  
  8.  
  9.                  A. Linking Techiques for Memory Management
  10.  
  11.                    1. Dynamic Overlaying of Clipper Code
  12.                    2. Dynamic Overlaying of C/ASM Code
  13.                    3. Using EMS or UMB Ram for Overlays
  14.                    4. Static Overlays
  15.                    5. Reloadable Overlays
  16.                    6. Overlaying Library Modules
  17.                    7. Speed Optimization
  18.  
  19.                  B. Programming Techniques for Memory Management
  20.  
  21.                    1. Symbol Management
  22.                    2. Memory effects of Database usage
  23.  
  24.  
  25.      ╔════════════════════════════════════════════╗
  26.      ║  LINKING TECHNIQUES FOR MEMORY MANAGEMENT  ║
  27.      ╚════════════════════════════════════════════╝
  28.  
  29.         The Clipper compiler has the responsiblity of converting source
  30.         code to "machine-readable" code.  This .OBJect code can not
  31.         be "executed" by the machine however until it is "linked" to
  32.         other .OBJect code segments in the Clipper libraries.  This
  33.         is the responsibility of the linker.  Linking or "fixing up"
  34.         references made by your code to external variables and functions
  35.         is necessary to insure that your compiled program will address or
  36.         call other programs, including functions in the Clipper libraries
  37.         and DOS functions.
  38.  
  39.         A linker's basic job is to combine objects which have been
  40.         compiled separately.  Objects contain symbols of three types:
  41.  
  42.         a.  PUBLIC symbols - those symbols which are callable from
  43.                              other objects
  44.  
  45.         b.  STATIC symbols - those symbols which are callable only
  46.                              from within the same object
  47.  
  48.         c.  UNDEFINED symbols - symbols which exist in other objects
  49.                              and are referenced or used by this object
  50.                              (also referred to as EXTERNAL symbols).
  51.  
  52.         The Role of Linkers in developing large applications has taken
  53.         a new turn in the past few years.  In addition to providing
  54.         segment-linking, they are now also expected to provide the
  55.         best "memory image" possible.  This means that the linker must
  56.         be sophisticated in it's management of code segments during
  57.         the running of an application.  The physical size of a
  58.         Clipper application is no longer representative of it's memory
  59.         image, because the linker "overlays" the code segments to
  60.         use the smallest possible amount of memory.  Some type of
  61.         code (such as Clipper P-CODE) is easy to overlay while other
  62.         types (ASM) may be more difficult.  Applications that are
  63.         almost all Clipper-compiled code will usually produce the best
  64.         memory image regardless of the physical size of the .EXE.
  65.  
  66.         The subjects of this seminar are the two most commonly-used
  67.         linkers available on the market today for linking Clipper 5.0
  68.         applications.  They are:
  69.  
  70.          RTLINK -   A Clipper-5.0 specific linker developed by
  71.                     Pocketsoft, Inc.  This is the linker that is
  72.                     bundled with Clipper 5.0.
  73.  
  74.          BLINKER -  A Third-Party Clipper-specific linker published
  75.                     by Blink, Inc. for Summer 87 and 5.0 applications.
  76.  
  77.  
  78.       ╔══════════════════════════════════════╗
  79.       ║  DYNAMIC Overlaying of Clipper Code  ║
  80.       ╚══════════════════════════════════════╝
  81.  
  82.         Very large Clipper applications can consist of more code than
  83.         can be loaded into the available amount of DOS memory and may
  84.         not be able to execute due to insufficient memory.  Clipper
  85.         5.0 has a "Dynamic Overlay Manager" actually built into the
  86.         Clipper libraries that helps prevent this problem by loading
  87.         the code into memory only as it is needed by the application
  88.         that is running.  The linker helps prepare the application
  89.         to use this capability of 5.0 by splitting the Clipper-compiled
  90.         application code into fixed-size "pages" that share a pre-
  91.         allocated area of memory.  These pages of code are then
  92.         written to a seperate .OVL file or to the end of the .EXE
  93.         file as determined by your linker options.  When a procedure or
  94.         function is called, the "dynamic-overlay manager" first checks
  95.         to see if it is in memory.  If it is, then it jumps to the
  96.         called function.  If it is not in memory, it loads the function
  97.         from disk into any "free" location available in the overlay
  98.         pool.  If no free space can be found in the overlay pool, the
  99.         overlay manager discards pages that have not been called
  100.         recently to free space to load the called procedure.
  101.  
  102.         The larger the overlay pool, the less often the overlay manager
  103.         needs to load from disk and the faster your program will run.
  104.         The size of the dynamic overlay pool needed for your application
  105.         is automatically determined by Clipper.
  106.  
  107.         The great thing about Clipper 5.0's dynamic overlaying system is
  108.         that you, the programmer, don't need to do anything to create
  109.         overlays.  It is all done automatically by the linker.  Only
  110.         Clipper-compiled modules, not C/ASM modules, are overlayed
  111.         "dynamically", although since much of the Clipper libraries has
  112.         been compiled in Clipper, even large portions of the Clipper
  113.         libraries will be dynamically overlayed.
  114.  
  115.         Application libraries and third-party libraries written in
  116.         Clipper will also be automatically overlayed by RTLINK and
  117.         BLINKER. In many cases it is more beneficial to write functions
  118.         in Clipper (using LOCAL memvars) than in C or ASM because it
  119.         will not increase the executable memory model.  Even Clipper
  120.         code that has been linked into to Pre-link libraries will be
  121.         dynamically overlayed.
  122.  
  123.  
  124.         INTERNAL/EXTERNAL Overlays
  125.         ---------------------------
  126.  
  127.         INTERNAL overlays are dynamic pages which are written to the end
  128.         of the .EXEcutable program file.  During the running of the
  129.         application, the dynamic overlay manager reads the disk and loads
  130.         dynamic pages from this file.   This is the default overlay
  131.         method of RTLINK and BLINKER and it is often advantageous to use
  132.         internal overlays to reduce the number of file handles being
  133.         opened by your application.  In some cases however, you may
  134.         find that using multiple overlay files will increase the
  135.         speed performance of your application because extracting code
  136.         from several small files which are all opened at the same time
  137.         is often faster that extracting code from one large file.
  138.  
  139.         EXTERNAL overlays are sets of dynamic pages which are written to
  140.         a seperately designated file more commonly referred to as an
  141.         overlay file.  The positional command /DYNAMIC[:<ovlfile>] or the
  142.         freeformat command DYNAMIC INTO <ovlfile> will tell RTLINK to
  143.         write the dynamic pages to a file named <ovlfile>.  You may
  144.         wish to create a seperate overlay file when your application
  145.         .EXE is too large to fit on a distribution disk.
  146.  
  147.         Examples:
  148.  
  149.          Rtlink>   DYNAMIC INTO myprog.ovl
  150.          Blinker>  SECTION INTO myprog.ovl
  151.  
  152.          Rtlink>   DYNAMIC INTO myprogs.ovl MYPROG1, MYPROG2
  153.                    DYNAMIC INTO myfuncs.ovl MYFUNC1, MYFUNC2
  154.          Blinker>  SECTION INTO myprogs.ovl MYPROG1, MYPROG2
  155.                    SECTION INTO myfuncs.ovl MYFUNC1, MYFUNC2
  156.  
  157.  
  158.  
  159.       ╔══════════════════════════════════════╗
  160.       ║  DYNAMIC Overlaying of C / ASM Code  ║
  161.       ╚══════════════════════════════════════╝
  162.  
  163.         BLINKER also provides the ability to dynamically overlay code
  164.         written in C or Assembly.  This is the most common code found
  165.         in many third-party libraries.  RTLINK also provides for
  166.         overlaying of C/ASM but it is more complex and requires
  167.         understanding more about the code being overlayed.  See
  168.         STATIC OVERLAYS and RELOADABLE OVERLAYS for more information
  169.         on overlaying C/ASM code with RTLINK.
  170.  
  171.         In the previous chapter, we discussed that application code
  172.         compiled with the Clipper-compiler is dynamically overlayed
  173.         using the overlay manager built inside the Clipper libraries.
  174.         This Clipper-specific internal overlay manager is incapable
  175.         of overlaying C/ASM code, so it is the responsibility of the
  176.         linker to provide this capability.  Each linker has it's own
  177.         methods for overlaying this kind of code.  BLINKER uses an
  178.         overlay pool that is allocated at the start of the application.
  179.         The size of this pool is determined at link-time.  The larger
  180.         the overlay pool, the faster the application will run because
  181.         overlays will not be reloaded into memory from disk so often.
  182.  
  183.         The dynamic-overlay capabilities of BLINKER require that the
  184.         objects being overlayed are "well-behaved".  After much
  185.         experimentation with our own libraries and many third-party
  186.         libraries, it is now more clear what constitutes well-behaved
  187.         modules:
  188.  
  189.          a. Well-behaved code uses the Clipper EXTEND interface,
  190.             registers or the stack for parameter passing and does
  191.             not use undocumented features of Clipper.
  192.  
  193.          b. All Clipper-compiled .OBJects are dynamically-
  194.             overlayable.
  195.  
  196.         Modules which CANNOT be dynamically-overlaid are:
  197.  
  198.          a. Routines which handle interrupts.
  199.  
  200.          b. Modules in which the DATA area is changed during
  201.             runtime rather than allocating memory in the root area.
  202.  
  203.         Dynamic overlaying of third-party libraries can be an
  204.         aggravating learning experience if you don't get support from
  205.         the third party vendor in trying to accomplish this task.
  206.         Most of the third-party vendors now break their libraries
  207.         into separate overlayable and non-overlayable .LIB files to
  208.         make the task much easier.
  209.  
  210.         Once you have determined which .OBJ files and/or .LIB files
  211.         are acceptable for overlaying, the task of telling the
  212.         linker to do this is quite simple.  A BLINKER link-script
  213.         will look similar to an RTLINK script except there is always
  214.         only one (1) overlay area because all code uses the same
  215.         overlay "pool".
  216.  
  217.         Example of a BLINKER script for overlaying C/ASM:
  218.  
  219.         # Allocate 50k to the overlay pool
  220.         BLINKER OVERLAY OPSIZE 50
  221.         BEGINAREA
  222.           # Clipper-compiled application code
  223.            FILE myprog1.obj, myprog2.obj
  224.           # C/ASM files
  225.            FILE ccode.obj, asmcode.obj
  226.           # C/ASM libraries
  227.            LIB ccode.lib, asmcode.lib
  228.         ENDAREA
  229.  
  230.  
  231.       ╔══════════════════════════════════════════╗
  232.       ║  Using EXPANDED or UMB RAM for OVERLAYS  ║
  233.       ╚══════════════════════════════════════════╝
  234.  
  235.         BLINKER provides a several very useful feature for increasing
  236.         the amount of available memory for Clipper applications, i.e.,
  237.         the use of Expanded (EMS) or Upper Memory Blocks (UMB).
  238.  
  239.         -- EMS --
  240.  
  241.         Many computers have EMS memory.  EMS memory managers such as
  242.         QEMM, 386MAX and DOS 5.0 create a memory area above
  243.         conventional memory referred to as the "page frame".  This 64k
  244.         block of memory is mapped to an area of ram that can execute
  245.         8086 code.  Blinker takes advantage of this feature by
  246.         allocating the 64k EMS page frame rather than conventional DOS
  247.         memory for their runtime overlay pool.  This frees an additional
  248.         64k of memory for use by Clipper because the overlays are loaded
  249.         into the page frame rather than conventional ram.  If no EMS is
  250.         present when the application starts, then the overlay pool will
  251.         be established in normal (conventional) ram.  To enable this
  252.         feature, use the Blinker command:
  253.  
  254.           BLINKER OVERLAY PAGEFRAME ON
  255.  
  256.         -- UMB --
  257.  
  258.         Expanded memory managers will also create an area between the
  259.         640k and 1 meg memory address called UMB (upper memory blocks).
  260.         This is the area where you would normally load your memory-
  261.         resident programs such as DOS, network-drivers, etc.  If your
  262.         enviroment gives you about 40k - 60k of contiguous memory
  263.         available in the UMB area, Blinker will load the overlay pool
  264.         into the UMB area rather than conventional area, thus freeing
  265.         more memory for your Clipper application.  To enable this
  266.         feature, use the Blinker command:
  267.  
  268.           BLINKER OVERLAY UMB ON
  269.  
  270.  
  271.       ╔═══════════════════╗
  272.       ║  STATIC Overlays  ║
  273.       ╚═══════════════════╝
  274.  
  275.         STATIC overlays are supported by RTLINK only.  They provide a
  276.         method of overlaying C and ASM code which cannot be overlayed by
  277.         the dynamic-overlay manager.  C and ASM code is not as easily
  278.         relocatable as Clipper compiled PCODE (pseudo-code) therefore it
  279.         cannot be overlayed "dynamically".  A function which is
  280.         dynamically loaded and unloaded from a pool is usually found in
  281.         different places in memory at different times during the running
  282.         of the program.  When a C or assembly routine is called by an
  283.         application linked with RTLINK it must be loaded in memory at
  284.         the same address every time.  This is accomplished by
  285.         designating overlay AREAS where many different modules will
  286.         occupy the same memory space, but only one-at-a-time.
  287.         Designing Static overlays requires a more thorough understanding
  288.         of the structure of your program.
  289.  
  290.         Static overlay segments usually look like this in your link
  291.         file:
  292.  
  293.           # area 1
  294.           BEGINAREA
  295.             SECTION FILE A
  296.             SECTION FILE B
  297.             SECTION FILE C
  298.           ENDAREA
  299.  
  300.           # area 2
  301.           BEGINAREA
  302.             SECTION FILE D
  303.             SECTION FILE E
  304.             SECTION FILE F
  305.           ENDAREA
  306.  
  307.         You must be sure that you properly place your objects in the
  308.         overlay segments to prevent computer "lock-up" or "crashing"
  309.         at runtime.  In the above example, any procedure or function in
  310.         FILE A may call any procedure or function in FILE D, E or F
  311.         because they are in different areas, however if a function in
  312.         FILE A calls a procedure or function in FILE B, then your program
  313.         will crash as soon as the program returns to FILE A because FILE A
  314.         was removed from memory to load FILE B.
  315.  
  316.         Overlay management with "static overlays" is the most time-
  317.         consuming because it requires extensive analysis of the
  318.         structure of the program to insure that the modules are placed
  319.         properly in the overlay areas.
  320.  
  321.  
  322.  
  323.       ╔═══════════════════════╗
  324.       ║  RELOADABLE Overlays  ║
  325.       ╚═══════════════════════╝
  326.  
  327.         The following overlaying technique may be considered
  328.         controversial because it is an "unsupported" and "undocumented"
  329.         feature of the RTLINK linker supplied with Clipper-5.0.  I feel
  330.         however, that it is important to cover this subject because
  331.         without an understanding of how to use this feature it may be
  332.         impossible to develop certain types of Clipper applications.
  333.         dCLIP is an example of a Clipper application that would not have
  334.         been possible if I could not use "reloadable" overlays.  Please
  335.         be aware that this subject material is not supported by
  336.         Nantucket and is provided as information to be used at your own
  337.         risk.
  338.  
  339.         I have been RELOADING objects from the Summer 87 Clipper libraries
  340.         for years, so when I received my copy of Clipper-5.0, the first
  341.         thing I attempted to do was to overlay some of the larger C/ASM
  342.         modules in the Clipper libraries using the RELOAD command in
  343.         my linker script file.  The Nantucket development team had the
  344.         foresight to insure that their C and ASM compiler assigned a
  345.         UNIQUE name to each Clipper C/ASM object in the Clipper libraries,
  346.         thus allowing, you, the Clipper programmer to use both the
  347.         RELOAD command and MODULE command in your .LNK script files.
  348.  
  349.         So what are "Reloadable Overlays"?  These are a form of STATIC
  350.         overlay in which segments of code are placed into overlay sections
  351.         that occupy the same memory space at runtime, however the "calling
  352.         module" is automatically "reloaded" into memory when returning
  353.         from the "called module".
  354.  
  355.         Reloadable overlay segments usually look like this in your link
  356.         file:
  357.  
  358.           RELOAD FAR 200
  359.           # area 1
  360.           BEGINAREA
  361.             SECTION FILE A
  362.             SECTION FILE B
  363.             SECTION FILE C
  364.           ENDAREA
  365.  
  366.           # area 2
  367.           BEGINAREA
  368.             SECTION FILE D
  369.             SECTION FILE E
  370.             SECTION FILE F
  371.           ENDAREA
  372.  
  373.  
  374.         Not all Clipper applications are going to need to use these
  375.         reloadable static overlays, but if your application relies
  376.         heavily on third-party libraries written in C/ASM, then it is
  377.         recommended that you learn this technique.
  378.  
  379.         The main advantage of "reloadable overlays" over conventional
  380.         "static overlays" is that you are never in danger of "lockup"
  381.         in the event that a procedure or function in FILE A calls a
  382.         function or procedure in FILE B because FILE A will be reloaded
  383.         into memory on return from FILE B.  Make sure when you use the
  384.         RELOAD command that you always use it as follows:
  385.  
  386.           RELOAD FAR <stack size>
  387.  
  388.         where the <stack size> is the amount of memory in hex bytes to
  389.         use for saving addresses.  My experience is that most
  390.         applications will run just fine with a stack size of 200.  If
  391.         your application does recursive nesting, however, you may need
  392.         to increase the stack size.  Recursive nesting is described as
  393.         follows:  Procedure A calls Procedure B which calls Procedure A
  394.         which calls Procedure B, etc, etc, etc.  Each time a procedure
  395.         is called, its return address is "pushed" onto the stack, and
  396.         each time you return to the calling procedure the address is
  397.         "popped" from the stack.  In the above example, if this
  398.         recursive condition were allowed to continue for a large number
  399.         of iterations, the stack would be overrun and the program may
  400.         crash.
  401.  
  402.         Although your application will not crash using RELOAD, it may
  403.         slow down a bit if overlay segments are not structured properly,
  404.         because each time an overlay is reloaded the application must
  405.         go to disk.  In the above example if a function in FILE A
  406.         repetitively calls a function in FILE B then your application
  407.         will be very "disk intensive" and will run slowly.  If a
  408.         function in FILE A repetitively calls a function in FILE D there
  409.         will be no slowing at all because both modules will remain in
  410.         memory.
  411.  
  412.         Overlay management of C/ASM code with "reloadable overlays" is
  413.         less time-consuming and more reliable than simple conventional
  414.         "static overlays" and provides an additional advantage of
  415.         allowing more modules to be overlayed, thereby saving additional
  416.         memory usage.
  417.  
  418.  
  419.  
  420.       ╔════════════════════════════╗
  421.       ║ OVERLAYING LIBRARY MODULES ║
  422.       ╚════════════════════════════╝
  423.  
  424.         The MODULE command provides the important capability of
  425.         overlaying the larger modules of CLIPPER.LIB or any other
  426.         third-party library.  With previous versions of these linkers,
  427.         the overlaying of libraries was restricted to ALL modules in a
  428.         library or NO modules in a library.  This is ok for libraries
  429.         which were designed for overlaying, but in most cases it is
  430.         simply not practical to overlay an entire library due to speed
  431.         performance problems.  There are many modules in CLIPPER.LIB
  432.         which can be overlayed without crashing the program, yet runtime
  433.         performance can be disastrous.  Determining the proper "set" of
  434.         modules and the optimum "overlay pool size" is simply a matter
  435.         of trial and error.  For example, overlaying the MACRO module in
  436.         one application may have very little affect on speed performance
  437.         because of the design of the program and it's probable negligible
  438.         On the contrary, it was completely unacceptable to overlay MACRO
  439.         in the dCLIP engine because dCLIP relies heavily on the MACRO
  440.         compiler for many of it's interpretive operations.
  441.  
  442.         The MODULE command is very useful in that it allows your linker
  443.         to place "modules" from libraries into overlays.   You can
  444.         organize your projects by placing all your C/ASM objects in
  445.         libraries with a library manager such as Microsoft's LIB.EXE
  446.         then by using the SECTION MODULE <module> command in your link
  447.         file you can place any module into any overlay area.
  448.  
  449.         Rtlink:
  450.  
  451.           LIB mylib
  452.           BEGINAREA
  453.             SECTION MODULE myfileA,myfileB
  454.             SECTION MODULE myfileC
  455.             SECTION MODULE myfileD
  456.           ENDAREA
  457.  
  458.         The MODULE <module> command in RTLINK requires that the <module>
  459.         exists in one of the declared libraries and that the name is
  460.         "unique" to that module otherwise the command will be ignored and
  461.         the module will be linked into the root memory area.  This is not
  462.         a problem with the Clipper libraries because the modules are given
  463.         unique names.
  464.  
  465.         BLINKER supports the MODULE command differently and, in my
  466.         opinion, better than RTLINK.  Blinker allows you to define a
  467.         specific module from a specific library to be linked into the
  468.         application, thus you don't need to worry about the module being
  469.         unique to one library.  For example, if you have two libraries,
  470.         both containing an ERRORSYS module, you can decide which ERRORSYS
  471.         you want linked into the program.
  472.  
  473.         Blinker:
  474.  
  475.           LIB mylib
  476.           BEGINAREA
  477.             LIB grump
  478.             MODULE errorsys FROM grump
  479.             MODULE myfileA,myfileB
  480.             MODULE myfileC
  481.             MODULE myfileD
  482.           ENDAREA
  483.  
  484.  
  485.         DETERMINING THE MODULE NAMES IN A LIBRARY
  486.         ------------------------------------------
  487.  
  488.         Every ".OBJect" file placed into a library is also assigned a
  489.         "module" name.  This module name is stored in the "COMENT"
  490.         record of the object in the library.  The "module" name of an
  491.         object is assigned by the compiler of the object and is usually
  492.         given the name of the original source code.   The Clipper
  493.         compiler assigns the same name as the .OBJ file, however many
  494.         compilers will assign the name of the SOURCE file as the module
  495.         name including drive letters and directories.  For example, let's
  496.         say we want to place the Funcky FINDATTR() function into an
  497.         overlay.  First, we must figure out what "module" name was
  498.         assigned to the FINDATTR() function.  There are library manager
  499.         utility programs which can help you figure this out, but I'm
  500.         going to show you how to do it simply with your linker.
  501.         During VERBOSE linking the "module" name of each object being
  502.         linked into the program is displayed on the screen as follows:
  503.  
  504.           FUNCKY50.LIB(C_MAXCHO)         <- Clipper code
  505.           FUNCKY50.LIB(C_PUTKEY)         <- Clipper code
  506.           FUNCKY15.LIB(findattr.C)       <- "C" code
  507.           FUNCKY15.LIB(finddate.C)       <- "C" code
  508.           FUNCKY15.LIB(findfirs.C)       <- "C" code
  509.           FUNCKY15.LIB(chrfound.ASM)     <- "Assembly" code
  510.           FUNCKY15.LIB(strcente.ASM)     <- "Assembly" code
  511.  
  512.  
  513.         You must make sure that you insert the command VERBOSE into your
  514.         link script file to insure that this information is displayed.
  515.         Next, when you perform the link, make sure route the dislay
  516.         output to a file so you can have the information in text file
  517.         format:
  518.  
  519.           RTLINK @MYPROG > MYPROG.TXT
  520.  
  521.         MYPROG.TXT will contain the complete list of modules linked into
  522.         your program.  Now, we must take this information and use it to
  523.         develop an overlay strategy.  The name of each module linked into
  524.         the program is shown (in parenthesis) and must be referred to
  525.         "exactly" as it is spelled.  For example, to place the function
  526.         FINDATTR() into an overlay, we must first determine the "module"
  527.         name which would contain the FINDATTR() function.  Fortunately,
  528.         the FUNCKY15 library uses the same prefix name as the actual
  529.         function, so in perusing the list of linked objects in MYPROG.TXT
  530.         we find a module named "findattr.c".  To place this module in an
  531.         overlay section, simply use the command:
  532.  
  533.             SECTION MODULE findattr.c
  534.  
  535.         BLINKER's  MODULE command is more useful than RTLINK's because
  536.         it searches both the THEADR record and the COMENT record for the
  537.         name of each module.  This means that you don't need to
  538.         reference the MODULE name as precisely with these linkers as with
  539.         RTLINK.  For example, if the module name in a library is
  540.         FINDATTR.C, BLINKER will overlay it by with the following
  541.         command:  MODULE FINDATTR,  because it will determine that what
  542.         you are trying to overlay is FINDATTR.OBJ.
  543.  
  544.  
  545.         OVERLAYING THE CLIPPER LIBRARIES
  546.         ---------------------------------
  547.  
  548.         Overlaying the Clipper libraries is accomplished quite
  549.         differently with each linker, therefore I have included
  550.         examples for each linker.
  551.  
  552.         ----------
  553.           RTLINK
  554.         ----------
  555.  
  556.         RTLINK uses Static reloadable overlays with and the MODULE
  557.         command to overlay much of the Clipper libraries and thereby
  558.         reduce memory usage in your Clipper-5.0 applications.  The
  559.         below link script example creates an overlay area for overlaying
  560.         the larger modules in the Clipper libraries which are not likely
  561.         to call each other recursively, therefore you will probably
  562.         notice very little difference in speed performance yet you will
  563.         get up to 50K more memory overhead depending on how much of the
  564.         Clipper libraries your application uses.
  565.  
  566.         You may get a "warning" message during link time if your
  567.         application does not call one of the modules referenced in an
  568.         overlay area.  In the event this happens, simply remove that
  569.         module from the link file.  For example, if you are not using
  570.         MEMOEDIT() in your application remove the line:
  571.  
  572.              SECTION MODULE 50\MEMOEDIT
  573.  
  574.  
  575.  
  576.           FI <my files>
  577.           LIB <my libs>
  578.           OUTPUT <my .EXE>
  579.           RELOAD FAR 200
  580.           BEGINAREA
  581.             SECTION MODULE 50\MEMOEDIT, 50\MEMOTRAN, 50\MEMOREAD
  582.                     MODULE 50\MEMOWRIT, 50\MEMOLINE, 50\MLCOUNT
  583.                     MODULE 50\MLPOS
  584.             SECTION MODULE 50\IS, 50\EXAMPLEC, 50\HARDCR, 50\PAD
  585.                     MODULE 50\PADL, 50\PADC, 50\PADR, 50\ASCAN
  586.                     MODULE 50\ASORT, 50\DIRECTRY, 50\AEVAL, 50\ACOPY
  587.                     MODULE 50\ADEL, 50\AINS, 50\COPYFILE, 50\TYPEFILE
  588.                     MODULE 50\SCROLL, 50\GETE, 50\DISKSPAC
  589.             SECTION MODULE 50\SDF1, 50\SDF0, 50\SDFDYN, 50\DLM1
  590.                     MODULE 50\DLM0, 50\DELIMDYN, 50\DBCREATE
  591.                     MODULE 50\DBJUNCT, 50\DBSTRUCT, 50\ACHOICE
  592.             SECTION MODULE 50\NET, 50\ACCEPT, 50\DATE, 50\OSDATE
  593.             SECTION MODULE 50\FGET, 50\OLDBOX, 50\OLDCLEAR, 50\RUN
  594.                     MODULE 50\SEND, 50\JOINLIST, 50\SORTOF, 50\SORTBLOC
  595.           ENDAREA
  596.           BEGINAREA
  597.             SECTION MODULE 50\TBROWSE0
  598.             SECTION MODULE 50\TBROWSE1
  599.             SECTION MODULE 50\EXAMPLEA, 50\PHILES, 50\DBF0, 50\DTX0
  600.                     MODULE 50\INITEXIT, 50\TXOPEN, 50\BOX, 50\STRTRAN
  601.           ENDAREA
  602.  
  603.         When placing modules into overlays, you must use extreme care to
  604.         not overlay functions which are called by "interrupts" or may be
  605.         called "recursively".  Code which is called by interrupts is
  606.         called by a direct vector rather than an overlay vector this can
  607.         cause computer lockup if the code segment is not currently in
  608.         memory.  Code which is called recursively would be something like
  609.         special string handling routines that might be called in a
  610.         do..while loop.  If this function were placed in an overlay, you
  611.         may experience considerable slowing and/or disk access.
  612.  
  613.         Many third-party library developers now distribute their product
  614.         in two libraries: a "resident" library and an "overlayable"
  615.         library.  Most of the work has already been done for you in
  616.         determining which modules can be overlayed.  If the module is part
  617.         of the "resident" library, don't make any attempt to try to
  618.         overlay it or you will experience runtime problems.  Also, don't
  619.         make an attempt to overlay "Clipper code" because this code is
  620.         automatically overlayed into "dynamic-pages".
  621.  
  622.  
  623.         -----------
  624.           BLINKER
  625.         -----------
  626.  
  627.         Overlaying the Clipper libraries with Blinker is simpler than
  628.         Rtlink because only one overlay area needs to be defined for
  629.         all overlayable modules, files and libraries.  Like Rtlink,
  630.         Blinker will automatically overlay any code in any library
  631.         that is compiled with the Clipper compiler.
  632.  
  633.           BLINKER OVERLAY OPSIZE 50
  634.           BLINKER PROCEDURE DEPTH 50
  635.           FI <my root files>
  636.           LIB <my root libs>
  637.           OUTPUT <my .EXE>
  638.           BEGINAREA
  639.              FILE <my overlayable files>
  640.              ALLOCATE <my overlayable libraries>
  641.              # Modules from CLIPPER.LIB
  642.              MOD accept,acopy,adel,aeval,ains,appinit,atail,box,cmem,date
  643.              MOD dbcmd2,dbcmd3,dbcmd4,dbcmd5,dbcreate,dbf0,dbfdyn,dbjunct
  644.              MOD dbstruct,dtx0,dtx1,dtxdyn,dynina,errsys0,errsys1,fget
  645.              MOD getenv,gets0,gets1,gets2,gx,joinlist,lupdate,memory
  646.              MOD mrelease,msave,net,oldbox,oldclear,philes,run,saverest
  647.              MOD sdf0,sdf1,seq,setcurs,sortbloc,startsym,tb,txopen,vall
  648.              MOD vblock,vdb,vdbg,version,vmacro,vnone,vops,vpict,vterm
  649.              MOD workarea,xmacro
  650.              ALLOCATE extend
  651.            ENDAREA
  652.            LIB clipper, terminal ,dbfntx
  653.  
  654.  
  655.       ╔══════════════════════╗
  656.       ║  SPEED OPTIMIZATION  ║
  657.       ╚══════════════════════╝
  658.  
  659.         Most features of the new generation of linkers are designed
  660.         for memory optimization.  Unfortunately, improving memory
  661.         performance "almost always" works against speed performance
  662.         when the job is being handled by the linker.  Overlaying of
  663.         code requires that code segments be swapped in and out of
  664.         memory and that "overlay vectors" rather than "direct vectors"
  665.         are used to access the code.  This increased overhead will
  666.         slow down the application and often-times create unacceptable
  667.         runtime performance.
  668.  
  669.         Simply overlaying an entire library is not always the best
  670.         choice when speed performance is critical.  For example, a
  671.         function that skips a record pointer through a database must
  672.         be called once for each record.  If this function is in an
  673.         overlay then the speed of browsing a database, locating a
  674.         record, or reindexing a file can be greatly affected because
  675.         the function must be called via the overlay manager.  Speed
  676.         is not usually a problem when overlaying code that has been
  677.         compiled by Clipper, because the Clipper-code overlay manager
  678.         is actually part of the Clipper libaries and is very efficient
  679.         in the manner in which it dynamically overlays pages of P-CODE
  680.         (Clipper .OBJs).  C and ASM native code on the other hand must
  681.         be overlayed by the linker's overlay manager and can greatly
  682.         affect performance if an often-used function is not in the
  683.         "root" memory area.
  684.  
  685.         In my opinion, there is no good rule-of-thumb for determining
  686.         which modules should be overlayed other than the time-tested
  687.         method of "trial and error".  I have spent hours and hours
  688.         testing different overlay strategies to end up with the
  689.         just-right balance of speed vs memory optimization.  This
  690.         investment of time has always payed me great dividends because
  691.         from then on I was confident that I done my homework and that
  692.         my application was "perfectly tuned".
  693.  
  694.         The linkers included in this discussion offer some other fine
  695.         features that can provide improved speed performance without
  696.         sacrificing memory performance, however, they require that you
  697.         utilize some of the advanced features of your computer
  698.         hardware to get the benefit.
  699.  
  700.         1. OVERLAY CACHING
  701.  
  702.         Both RTLINK and BLINKER (release 2.0) support the feature of
  703.         "caching" overlays to improve runtime speed on computers with
  704.         EMS or XMS memory.  A "cache" is an area of memory that has
  705.         been pre-allocated for storing code segments that have been
  706.         overlayed and need to be swapped out to make room in memory
  707.         for new code.  Rather than discarding the code segment and
  708.         then reloading from disk each time it is needed, it can be
  709.         reloaded from the "cache" memory.  Obviously, memory to memory
  710.         loading is much faster than disk to memory loading.
  711.  
  712.          Blinker
  713.          --------
  714.  
  715.          Blinker 2.0 uses the following commands for caching with XMS
  716.          (2.0 and higher):
  717.  
  718.           BLINKER CACHE XMS niMax[%], niMinLeave[%]
  719.  
  720.          For example the command BLINKER CACHE XMS 50%, 1024 will use
  721.          a maximum of 50% of all available XMS, but leave at least
  722.          1024KB available for other programs.
  723.  
  724.          Even faster caching is available by using EMS (extended memory)
  725.          drivers because memory is handled in large contiguous blocks
  726.          rather than the smaller 64k "pages" such as the XMS (expanded
  727.          memory) drivers.  Use the following command for caching using
  728.          EMS (4.0 and higher)
  729.  
  730.            BLINKER CACHE EMS niMax[%], niMinLeave[%]
  731.  
  732.  
  733.         Rtlink
  734.         -------
  735.  
  736.          Rtlink's caching system is only useful when using STATIC
  737.          overlays.  In a previous chapter, I showed you how to overlay
  738.          the Clipper libraries and third-party libraries using the
  739.          RELOAD command, BEGINAREA..ENDAREA, and the MODULE command.
  740.  
  741.          To improve overlaying performance of C/ASM code in STATIC
  742.          overlays, use the following Rtlink caching commands:
  743.  
  744.            CACHE EXPANDED <memory in K> | <% of available>
  745.            CACHE EXTENDED <memory in K> | <% of available>
  746.  
  747.  
  748.         2. OVERLAY POOL SIZE
  749.  
  750.           Blinker provides for control of the overlay pool size to
  751.           allow more code segments to remain in memory and prevent
  752.           excessive "swapping" in and out of the pool.  Increasing
  753.           the size of the overlay pool will usually have the affect
  754.           of improving speed performance, but not always.  This is
  755.           another of those "trial and error" options.  The disadvantage
  756.           of increasing the pool size is that the application memory
  757.           will be reduced, so don't use more overlay pool than is
  758.           needed for the application.
  759.  
  760.            Blinker:  BLINKER OVERLAY OPSIZE <nMemoryK>
  761.  
  762.  
  763.         3. FORCING SEGMENTS TO ROOT
  764.  
  765.            Many times when overlaying a library, it is desirable to
  766.            "exclude" code segments from being overlayed to improve
  767.            speed.  Most often, the reason for the exclusion is
  768.            because the segment is used globally by many routines or
  769.            in loops that perform thousands of operations.  Sometimes,
  770.            a segment is just so large that overlaying causes it to
  771.            be swapped in and out of memory much too often.  There are
  772.            several methods to help you with moving code from an
  773.            overlayed library to the "root" memory.
  774.  
  775.            Rtlink
  776.            -------
  777.            All modules in libraries that are Clipper-compiled .OBJs
  778.            will be automatically overlayed when the library is declared
  779.            with the LIB command in your link script.  To force a
  780.            Clipper module from a library to link to the root memory area,
  781.            use the RESIDENT command and the MODULE command as follows:
  782.  
  783.            # MYLIB.lib contains my clipper code
  784.            LIB MYLIB
  785.            RESIDENT
  786.            # force MYFUNCS.obj and MYPROCS.obj to the root
  787.            MODULE MYFUNCS, MYPROCS
  788.            # everything from now on is overlayed
  789.            DYNAMIC
  790.  
  791.            Blinker
  792.            -------
  793.            Specified modules in Clipper-compiled libraries and C/ASM
  794.            libraries which have been overlayed can be forced to root
  795.            memory by using the MODULE command "outside" the BEGIN...
  796.            ENDAREA.  Example:
  797.  
  798.            BEGINAREA
  799.              # overlay my Clipper application library
  800.              LIB MYLIB
  801.              # overlay my C library
  802.              LIB CFUNCS
  803.            ENDAREA
  804.            # force MYFUNCS.obj and MYPROCS.obj to the root
  805.            MODULE MYFUNCS, MYPROCS
  806.            # force CFUNCS.obj to the root
  807.            MODULE CFUNCS
  808.  
  809.            Blinker 2.0 also supports a handy feature for automatically
  810.            forcing segments that are smaller than a specified size to
  811.            the root area.  Very small rountines (less than 32 bytes)
  812.            take up more root space when they are overlaid, due to the
  813.            overlay manager table entries, than they would if they
  814.            were simply left in the root.  Additionally, very small
  815.            overlaid routines execute disproportionately slower, since
  816.            the time overhead in loading / calling them may be large
  817.            in comparison with the actual execution time of the routine.
  818.  
  819.            BLINKER OVERLAY THRESHOLD <nBytes> will allow you to force
  820.            all segments that are smaller than <nBytes> into the root.
  821.  
  822.   
  823.  
  824.  
  825.     ╔═══════════════════════════════════════════════╗
  826.     ║  PROGRAMMING TECHIQUES FOR MEMORY MANAGEMENT  ║
  827.     ╚═══════════════════════════════════════════════╝
  828.  
  829.  
  830.       ╔═════════════════════╗
  831.       ║  SYMBOL Management  ║
  832.       ╚═════════════════════╝
  833.  
  834.         For a dynamic-overlay manager to work effectively, it is
  835.         important that it load overlays at the smallest possible code-
  836.         segment level, i.e., the procedure/function rather than the
  837.         entire object.  This requires managing the symbol table
  838.         seperately from the code and data, therefore, these linkers
  839.         place the symbol table into the root memory area and each
  840.         function into a separate overlay segment.
  841.  
  842.         Symbols cannot be overlayed, therefore it is important that
  843.         you program in a manner consistent with producing the smallest
  844.         number of symbols in your Clipper-compiled objects.  Here are
  845.         some tips for reducing the symbol table size in your
  846.         applications.
  847.         
  848.  
  849.         1.  COMPILE SMALLER SEGMENTS ( C/ASM )
  850.  
  851.         If you are writing code in C or Assembly, then the overlay
  852.         manager must bring an entire code segment into memory at one
  853.         time.  If you have many large code segments, then the size
  854.         of the overlay pool may need to be increased.  Normally, the
  855.         requirements of the application dictate the size of the code
  856.         segments, but it should be noted that a little extra time
  857.         in optimizing the size of your code will usually pay off if
  858.         you have a large library of routines.
  859.  
  860.         Clipper-compiled code is loaded "dynamically" so this is not
  861.         a requirement when programming in Clipper.
  862.  
  863.  
  864.         2. USE CONSTANTS INSTEAD OF MEMVARS
  865.  
  866.         Clipper memory variables are always treated as "symbols".
  867.         Refrain from using a memory variable if a constant is
  868.         sufficient.  For example, an unnecessary symbol can be
  869.         eliminated by changing the code:
  870.  
  871.         escapekey=27
  872.         DO WHILE INKEY()#escapekey
  873.           *clipper code
  874.         ENDDO
  875.  
  876.         to:
  877.  
  878.         DO WHILE INKEY()#27
  879.          *clipper code
  880.         ENDDO
  881.  
  882.          or:
  883.  
  884.         #define K_ESC 27
  885.         DO WHILE INKEY()#K_ESC
  886.           *clipper code
  887.         ENDDO
  888.  
  889.  
  890.         3. USE ARRAYS INSTEAD OF MEMVARS
  891.  
  892.         Every different Clipper memvar name creates a "symbol", whereas
  893.         an array name creates only ONE symbol.  The following example
  894.         shows how to save considerable memory in a clipper application
  895.         by reducing the symbol count with an array.
  896.  
  897.         This code produces 10 symbols:
  898.  
  899.           mname = name
  900.           maddress = address
  901.           mcity = city
  902.           mstate = state
  903.           mzip = zip
  904.           @ 1,1 SAY 'Name   ' GET mname
  905.           @ 2,1 SAY 'Address' GET maddress
  906.           @ 3,1 SAY 'City   ' GET mcity
  907.           @ 4,1 SAY 'State  ' GET mstate
  908.           @ 5,1 SAY 'Zip    ' GET mzip
  909.           READ
  910.           REPL name WITH mname, address WITH maddress,;
  911.           city WITH mcity, state WITH mstate, zip WITH mzip
  912.  
  913.  
  914.         This code produces 6 symbols:
  915.  
  916.           PRIVATE gets[5]
  917.           gets[1] = name
  918.           gets[2] = address
  919.           gets[3] = city
  920.           gets[4] = state
  921.           gets[5] = zip
  922.           @ 1,1 SAY 'Name   ' GET gets[1]
  923.           @ 2,1 SAY 'Address' GET gets[2]
  924.           @ 3,1 SAY 'City   ' GET gets[3]
  925.           @ 4,1 SAY 'State  ' GET gets[4]
  926.           @ 5,1 SAY 'Zip    ' GET gets[5]
  927.           READ
  928.           REPL name WITH gets[1], address WITH gets[2],;
  929.           city WITH gets[3], state WITH gets[4], zip WITH gets[5]
  930.  
  931.  
  932.         The following code also produces 6 symbols, however the 5.0
  933.         pre-processor is used here to create both DEBUG and NON-DEBUG
  934.         versions of compiled object code.  In the following example
  935.         the pre-processor is used to convert the 5 memvars to an array
  936.         when compiling the final version.
  937.  
  938.         To compile the below code WITHOUT symbol substitution for
  939.         debugging purposes, compile as follows:
  940.  
  941.           CLIPPER <my app> /dDEBUG
  942.  
  943.         To compile the below code WITH symbol substitution for your
  944.         final application, compile as follows:
  945.  
  946.           CLIPPER <my app>
  947.  
  948.         The /dDEBUG switch has the same effect as the comand:
  949.  
  950.           #define DEBUG
  951.  
  952.         in your source code, however, it is much more convenient
  953.         because it allows you to make debug or non-debug versions of
  954.         your code simply from the DOS command line or .BAT files.
  955.  
  956.           #ifndef DEBUG  && compiling non-DEBUG version
  957.             LOCAL gets[5]
  958.             #define mname     gets[1]
  959.             #define maddress  gets[2]
  960.             #define mcity     gets[3]
  961.             #define mstate    gets[4]
  962.             #define mzip      gets[5]
  963.           #endif
  964.           mname = name
  965.           maddress = address
  966.           mcity = city
  967.           mstate = state
  968.           mzip = zip
  969.           @ 1,1 SAY 'Name   ' GET mname
  970.           @ 2,1 SAY 'Address' GET maddress
  971.           @ 3,1 SAY 'City   ' GET mcity
  972.           @ 4,1 SAY 'State  ' GET mstate
  973.           @ 5,1 SAY 'Zip    ' GET mzip
  974.           READ
  975.           REPL name WITH mname, address WITH maddress,;
  976.           city WITH mcity, state WITH mstate, zip WITH mzip
  977.  
  978.  
  979.  
  980.         4. USE THE SAME NAME MEMVARS WHENEVER POSSIBLE
  981.  
  982.         Again, every "different" Clipper memvar in a module creates a
  983.         symbol.  If an object contains several procedures, use the
  984.         same name for memvars even though they may not perform the same
  985.         or similar functions.   For example, procedure A and procedure
  986.         B both need 5 memvars.  If procedure A declares its memvars with
  987.         5 unique names and procedure B declares its memvars with 5
  988.         unique names, then 10 symbols are used in the linked
  989.         application.  To eliminate 5 symbols, make sure that procedure
  990.         B assigns the same name to the memvars as procedure A.   This
  991.         is not possible of course, if the memvars need to be public to
  992.         both procedures and perform different functions, only if they
  993.         are private.
  994.  
  995.  
  996.         5.  USE COMPLEX EXPRESSIONS INSTEAD OF MEMVARS
  997.  
  998.         The following three lines of codes represents the method that
  999.         most Clipper programmers choose to accomplish most programming
  1000.         tasks.  It makes sense to code this way for readability, but
  1001.         if you are writing a very large application, this technique
  1002.         can be very symbol-intensive.  The following three lines of
  1003.         code will read the disk file READ.ME into a memvar named
  1004.         READ_FILE, save the changed code into a file named EDIT_FILE,
  1005.         then write the changed code back to the disk file READ.ME.
  1006.  
  1007.           read_file=MEMOREAD('READ.ME')
  1008.           edit_file=MEMOEDIT(read_file)
  1009.           MEMOWRIT('READ.ME',edit_file)
  1010.  
  1011.         These three lines of code can be replaced by one complex
  1012.         expression which uses no symbols at all.
  1013.  
  1014.           MEMOWRIT("READ.ME",MEMOEDIT(MEMOREAD("READ.ME")))
  1015.  
  1016.         An additional advantage to coding this way is that less
  1017.         free-pool or VMM memory is used because the process of
  1018.         temporarily storing the text in READ_FILE and EDIT_FILE is
  1019.         completely eliminated.  If you find that creating complex
  1020.         expressions such as this are unreadable and hard to maintain
  1021.         then use the 5.0 pre-processor to accomplish the same task as
  1022.         follows:
  1023.  
  1024.           # DEFINE read_file MEMOREAD('READ.ME')
  1025.           # DEFINE edit_file MEMOEDIT(read_file)
  1026.           MEMOWRIT('READ.ME',edit_file)
  1027.  
  1028.         The above code is just as readable as the original three lines
  1029.         of code but will not create any symbols at compile time.  Try
  1030.         compiling this code with your Clipper 5.0 compiler and use the
  1031.         /P switch to write the pre-processed code to a .PPO file, then
  1032.         look at the .PPO file to see what is actually compiled.
  1033.  
  1034.  
  1035.         6. USE LOCALS AND STATICS INSTEAD OF PRIVATES AND PUBLICS
  1036.  
  1037.         Sometimes it is just not possible or practical to write code
  1038.         without using symbols, so if you find yourself in this
  1039.         situation, Clipper 5.0 provides the new feature of
  1040.         "LOCALIZING" symbols to the code segment which is currently
  1041.         being executed rather than placing the symbol in the main
  1042.         symbol table.  Local symbols are effectively "overlayed"
  1043.         because they are treated as part of the code segment rather
  1044.         than given a place in the main symbol table.
  1045.  
  1046.         Not only does this save valuable memory but it also improves
  1047.         speed performance because the public symbol table does not need
  1048.         to be searched each time a STATIC or LOCAL symbol is referenced
  1049.         in your code.  Of course, if the symbol you are referencing is
  1050.         needed for the entire application or is used in a macro, then it
  1051.         must be declared as PRIVATE or PUBLIC.  Symbols which are not
  1052.         declared at all are automatically assumed to be PRIVATE, so make
  1053.         sure you use the LOCAL declaration for all symbols in your code
  1054.         which you do not want to end up in the main symbol table.
  1055.  
  1056.         The following example shows how to save considerable memory in
  1057.         a clipper application by reducing the symbol count with LOCAL
  1058.         declarations.
  1059.  
  1060.         This code produces 6 main memory symbols:
  1061.  
  1062.          PRIVATE mcity,mstate,mzip
  1063.          mcity = city
  1064.          mstate = state
  1065.          mzip = zip
  1066.          @ 3,1 SAY 'City   ' GET mcity
  1067.          @ 4,1 SAY 'State  ' GET mstate
  1068.          @ 5,1 SAY 'Zip    ' GET mzip
  1069.          READ
  1070.          REPL city WITH mcity, state WITH mstate, zip WITH mzip
  1071.  
  1072.  
  1073.         This code produces 3 main memory symbols and 3 local symbols:
  1074.  
  1075.          LOCAL mcity := city, mstate := state, mzip := zip
  1076.          @ 3,1 SAY 'City   ' GET mcity
  1077.          @ 4,1 SAY 'State  ' GET mstate
  1078.          @ 5,1 SAY 'Zip    ' GET mzip
  1079.          READ
  1080.          REPL city WITH mcity, state WITH mstate, zip WITH mzip
  1081.  
  1082.  
  1083.      ╔══════════════════════════════════╗
  1084.      ║ MEMORY EFFECTS OF DATABASE USAGE ║
  1085.      ╚══════════════════════════════════╝
  1086.  
  1087.        Many programmers have taken an affection to "data-driven"
  1088.        programming to speed up the development of custom applications.
  1089.        As a developer of programming tools, rather than custom
  1090.        applications, I find that data-driven programming techniques
  1091.        don't serve me well due to the impact on both speed and memory
  1092.        performance.  This seminar is dedicated to memory issues so
  1093.        we won't discuss the speed issues.  Since Clipper evolved as
  1094.        an X-Base type language, the common approach to data-driven
  1095.        programming is to create an "engine" or "kernel" .EXE program
  1096.        that retrieves "custom" information about the application
  1097.        from a set of database files.  The more sophisticated the
  1098.        system, the more data files are required for configuring the
  1099.        application.  It is important to understand the impact of
  1100.        databases on memory usage when designing applications that use
  1101.        many databases.
  1102.  
  1103.        When a database is opened with the USE command, all the field
  1104.        names are placed into the public symbol table.  This allows
  1105.        database field names to be used in expressions in the same
  1106.        manner as memvars.  Because this symbol table is PUBLIC, the
  1107.        field names will remain in the symbol table, even after the
  1108.        database is closed.  Clipper employs no mechanism to remove
  1109.        symbols from the symbol table, only to add them.  As each
  1110.        database is opened the symbols are added, thereby reducing
  1111.        the remaining available root memory ( MEMORY(0) ).  It is
  1112.        conceivable that an application could run out of memory if
  1113.        many databases are opened and closed.  Fortunately, symbols
  1114.        of the same name are "reused" in the symbol table, so if you
  1115.        open and close the same database many times, the symbol memory
  1116.        space will not be reduced.  Keeping this in mind, it is a
  1117.        good practice to use databases with fields of the same name.
  1118.  
  1119.        To improve speed operation, some programmers will open data-
  1120.        dictionary databases at the start-up of the program, load
  1121.        the custom program configuration into arrays, then close the
  1122.        databases.  This action will reduce the amount of VMM memory
  1123.        needed for file buffers and lower the number of DOS handles
  1124.        required, but the symbols will still be added to the symbol
  1125.        table even though they may never be accessed by the program.
  1126.        A data-driven application in which the databases are used
  1127.        only during the start-up of the application could be re-designed
  1128.        to convert the database information to a text file to generate
  1129.        a "runtime" version of the application that will load the
  1130.        array(s) from a text file rather than databases, thereby
  1131.        eliminating the symbol-table problem.
  1132.  
  1133.  
  1134.