home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 3 / BBS in a box - Trilogy III.iso / Files / Util / G-H / Greyscale DW 2.3 / QuickBASIC Users < prev    next >
Encoding:
Text File  |  1993-08-21  |  14.5 KB  |  227 lines  |  [TEXT/ttxt]

  1. If you write and compile QuickBASIC applications OR if you are a user of a QuickBASIC compiled application, this is for you.
  2.  
  3. QuickBASIC compiled applications have a tendency to run out of memory with the Deskwriter.  Usually that is because either the memory was not allocated correctly or not enough Finder memory (GetInfo) was allocated.  If you are a user, only solutions 1, 2 and 3 are available to you unless you know the author of the program and can convince them to follow solution #4.
  4.  
  5. Solution #1:  Use the HP Spooler.  It uses High Memory instead of your application's memory and is lightning fast as well.
  6.  
  7. Solution #2:  For older versions of HP drivers, SuperLaserSpool also does not require your application's memory.
  8.  
  9. Solution #3:  Increase Finder memory allocation (GetInfo) by about 250K.  If that works, you're home free.  If it doesn't, then the problem is within the program itself and you might as well set the memory allocation back and follow another option.
  10.  
  11. Solution #4:  If you wrote the application yourself, read my article about QuickBASIC memory management in Ariel Publication's "Inside Basic" (late 1992).  You can order that issue (or better yet subscribe and back date to any pervious issues you wish) by calling 509-923-2249.  Ask for Ross and mention me.  He'll fix you up.
  12.  
  13. ••••••••••••••••••••••••••••••••••••••••••••••••••••
  14.  
  15. Here is the text only version of the memory article:
  16.  
  17. Handle Your Memory
  18. before…
  19. It Handles You
  20. by Ray DiBugnara
  21. Semicon Components, Inc.
  22.  
  23. If you think that a heap-stack collision has something to do with Archie’s old jalopy in farmer Tuttle’s hay field, this article is for you!
  24.  
  25. All applications occupy finite memory space and must allocate that space with some degree of precision or else the data stack and the application heap may collide and the computer bombs!  This, of course, refers to the infamous Bomb Box and/or everything locking up, going fuzzy, crackling like the sound of melting computer chips and, unfortunately,  your valuable data being dispatched to RAM heaven.
  26.  
  27. QuickBASIC gives you some of the answers you need with its “FRE(n)” statement but, alas, I find that it’s a bit lacking and the QB manual very vague at best.  Many QB’ers just program away hoping that the “basic” in BASIC language forgives them of any programming indiscretions and that their memory problems will just remain “a memory”.
  28.  
  29. The Macintosh, however, can supply all (and more than all) the information you will need to make your applications run like you know what you’re doing (even when you don’t).  All you need is a little knowledge on the subject.  Knowledge is power!  (A 4MB upgrade doesn’t hurt either.)
  30.  
  31. I have included a simplified Application Memory Map which gives you all the locations you need to worry about.  Below that diagram are listed the memory locations to “PEEKL()” into for that information. 
  32.  
  33. What ever you do, don’t “POKE” anything into these locations unless you enjoy the sense of discovery, the fireworks of a spectacular crash and the smell of burning plastic (I exaggerate for effect)!  The following map applies to a compiled application:
  34.  
  35. (Sorry…the map didn't paste but each sector is arrayed as shown in the list below)
  36.  
  37.     applTop#=currentA5#+32+144
  38.     currentA5#=PEEKL(&H904)
  39.     curStackBase#=PEEKL(&H908)
  40.     applLimit#=PEEKL(&H130)
  41.     heapEnd#=PEEKL(&H114)
  42.     applZone#=PEEKL(&H2AA)
  43.  
  44. The returned memory values read from highest location (applTop#) to lowest (applZone#).   You won’t necessarily need them all but it’s nice to know where they are.  The value “currentA5#” is a pointer within the global section.
  45.  
  46. When running in the QB Interpreter mode, only the FRE(n) statements return useful information to your program.  From here on, a fully compiled QB application is assumed.
  47.  
  48.      unUsedData# = FRE(0)
  49.      unUsedHeap# = FRE(-1)
  50.     unUsedStack# = FRE(-2)
  51.  
  52. By the way, while these numbers are all supposed to be returned as long integers (2^31 max), bugs in the QB compiler cause overflow errors with values much smaller than that so machines with more than 4MB of RAM may have problems.  Use the double precision variables to be safe and send letters to Microsoft (and your congressman if you think it will help) to expedite QuickBASIC 2.0!  Convert back to long integer for the CLEAR statement, however.
  53.  
  54. Steps to Managing  your Memory
  55.  
  56. Step 1:  How much data space do I need?
  57.  
  58. Every time any variable is DIMensioned, you use up Data space.  Any variable or array not DIMensioned but used anyway still uses up Data space.
  59.  
  60.     Data bytes to reserve for variables:
  61.     % = 2    & = 4    ! = 4
  62.     # = 8    $ = 12 + 1/character
  63.  
  64. Strings use a minimum of 12 per element but, as they fill up, take more and more space.  For example:
  65.  
  66.     alpha$="" takes up just 12 bytes of data.
  67.     alpha$="0123456789" takes 10 + 12 bytes.
  68.     alpha$="" recovers the 10 extra bytes.
  69.     alpha$(10) requires 120 bytes just for starters.
  70.     alpha$=fatAlpha$ makes 2 fat alphas.
  71.  
  72. You must calculate or, at least, estimate the amount of data space you will require.  Then add 10K because I bet you forgot the…!
  73.  
  74. Add up all these data requirements and call that total:
  75.     dataSpaceNeeded#
  76.  
  77. Step 2:  How much unused heap is needed?
  78.  
  79. Unused heap is where many DA’s and printer drivers reside.  Ever have a Laserwriter or Deskwriter complain that there’s not enough memory?  Worse yet, ever have one not even give you the decency of a complaint?
  80.  
  81. Now, I call this region “unused” because it wasn’t used originally by your application until it got used (huh?).  Sooner or later, though, it’s going to be used by one of the memory sucking little utilities that makes the Macintosh so much fun to use.
  82.  
  83. Besides DA’s and the like…this region is also where all your EDIT FIELD declarations reside.  (You too can be a memory sucker.)  For each EDIT FIELD declaration you will need in bytes:
  84.  
  85.     12 + 1/character...but 196 minimum
  86.  
  87. An edit field with 1000 characters takes up 1012 bytes while an edit field with 12 characters uses 196 bytes.  Remember:  if your edit field has just had 5000 bytes typed into it, when you save that using:
  88.  
  89.     saveEditField$=EDIT$(n)
  90.  
  91. The string saveEditField$ will now also contain 5000 bytes of text which directly subtracts from the data space as well.  In this example, a total of 10000 bytes are now kept busy.
  92.  
  93. An edit field can contain about 32000 bytes (2^15 less overhead)…the same as a string variable.  You need to make a knowledgeable guess as to how much space to reserve.  I like to reserve as a default 256 bytes because 256 = 2^8 and that sounds like real heavy computer lingo.
  94.  
  95. After adding up all your edit field requirements, allow at least another 100000 bytes for drivers and DA’s.  More if you want bullet proof operation with top heavy System Folder “portfolios.”  Call this total:
  96.  
  97.     unUsedHeapSpaceNeeded#
  98.  
  99. Step 3:  How much Stack space do I need?
  100.  
  101. Now that’s a good question.  Your application will seldom need more than the default value (about 14000) but…do you want someone else deciding this for you?  Besides, some library and MBLC codes require stack space as do some other piggyback utilities such as spelling checkers, etc.  
  102.  
  103. Also, if you CHAIN to other modules, the stack must be large enough to pass on the largest STORAGE entry too.  If  you keep getting Error 7 at the CHAIN statement, you need more stack space.  To find out how much more, re-compile the application with “Create Program List File” option turned on.  Then examine that list under STORAGE in the Symbol and Label Tables looking for MAIN.  Your main module needs to clear enough extra stack space for the largest STORAGE entry.
  104.  
  105. FRE(-2) tells you only how much stack is unused, but, combined with stackUsed#, you can get the total stack picture:
  106.  
  107.     stackUsed#=curStackBase#-applLimit#
  108.  
  109. Unless we’re CHAINing, we’ll just make things easy on ourselves and let:
  110.  
  111.      stackSpaceNeeded#=36000#.
  112.  
  113. Step 4:  How much code space do I use?
  114.  
  115. There is no direct readout of how much space your application code takes since the heap pointers don’t see the divider between the code space and the data space.
  116.  
  117. If you “sink” a test CLEAR to get, if you pardon the pun, a “core” sample, you can find this out easily.
  118.  
  119. CLEAR,10000&,10000&
  120. codeSpaceNeeded#=heapEnd#-applZone# -10000#
  121.  
  122. The 10000# of course is the data space we reserved with the CLEAR so the rest of the used heap must be application code.  This only works accurately if no variables have been declared yet.
  123.  
  124. Step 6:  How much Globals space is taken?
  125.  
  126. Not much actually.  If you want, you can just ignore this space.  However, if you’re a real computer nerd, you’ll include it.  This region includes the jump table, application parameters, application globals and QuickDraw globals.  Just call it globals and be done with it:
  127.  
  128. globalSpaceNeeded#=applTop#-curStackBase#
  129.  
  130. Step 7:  How much room do I have?
  131.  
  132. When you set the size for an application in the Finder (using Get Info), you allocate how much space your application will get.  If you are not using Multifinder or System 7, then your application will get all the remaining RAM. 
  133.  
  134. Applications you wrote that worked fine without Multifinder might run out of memory in Multifinder because, instead of getting all the RAM there is, you now only get all the RAM that the compiler thought you needed.  Usually it’s right too unless you trick it with big arrays, etc.
  135.  
  136. Your application needs to know how much memory it has.  Now a word of caution: the Finder’s Get Info size is in long bytes instead of short bytes where: 1,000K long bytes equals 1024K short bytes.  The West Coast tends to prefer the fatter long bytes while the East Coast gravitates toward the leaner short bytes.   (So does you computer by the way.)
  137.  
  138. Actually, Apple felt they needed to round things off because 1000K looks a lot more tidy than 1024K.  Exactly how they explain away that 783K looks better than 802K I’ll never know.
  139.  
  140. From the Application Memory Map, the total memory your application has to fondle is (in East Coast short bytes):
  141.  
  142.     totalApplSpace#=applTop#-applZone#
  143.  
  144. Now, you could stop the program right here if you already knew there wasn’t enough space (you “hard wired” a minimum value right into your program) and exit with an alert, etc.
  145.  
  146. If, on the other hand, you are going to dynamically size your data arrays and/or unused heap based upon available memory like the pros do, then you will want to make some decisions.
  147.  
  148.     Add It All Up…
  149.  
  150.     globalSpaceNeeded#
  151.     stackSpaceNeeded#
  152.     unUsedHeapSpaceNeeded#
  153.     dataSpaceNeeded#
  154.     codeSpaceNeeded#
  155.         
  156.     TOTAL:    totalApplSpaceNeeded#
  157.  
  158. If totalApplSpace#>totalApplSpaceNeeded#, life is treating you well.  You can take the extra space and add it to dataSpaceNeeded# to dimension larger arrays and/or you can add it to unUsedHeapSpaceNeeded#  (by not adding it to dataSpaceNeeded#) to speed up printing, etc.  If the data space doesn’t get it, then the unused heap space automatically will.
  159.  
  160. dataSpaceNeeded&=CLNG(dataSpaceNeeded#)
  161. stackSpaceNeeded&=CLNG(stackSpaceNeeded#)
  162. CLEAR,dataSpaceNeeded&,stackSpaceNeeded&
  163.  
  164. If there is not enough data space, put up an Alert telling the user how much more memory is needed and then quietly exit.
  165.  
  166. A word about CLEAR.  In the QB Interpreter (called the Environment for some strange reason), there is no life after CLEAR!  CLEAR erases all RETURN’s, WEND’s, etc. so if a CLEAR is in a subroutine, you will never find your way back unless the program is compiled first. (So that’s why I got a RETURN without GOSUB error!)  Moral is; put CLEAR’s at the beginning of the program.  If you should need any of the pointers after CLEAR, you have to fetch them again since they were cleared as well.
  167.  
  168. Another word about ERASE.  This is an incredible tool for reducing memory space or re-sizing arrays.  When you are finished with a dynamic array, just erase it and you get back all that data space. (Just try that one ZBasic!)
  169.  
  170. Conclusion
  171. Well, there you have it (I think). Memory “mangle-ment” made easy.  (Well, at least possible.)  If all this seems such a pain, then just reserve 1000K in the Finder and CLEAR,400000&,40000& and be done with it.  When you are ready to publish your application, drag out this article again and then clean up the memory.
  172.  
  173. ••••••••••••••••••••••••••••••••••••••••••••••••••••
  174.  
  175. The following SUB() can be used to show you your memory status at any time by making calls to it.  The Option key activates it when a call is made to it otherwise it is ignored:
  176.  
  177. CALL ShowMemory("This Is A Sample Title Listing")
  178. END
  179.  
  180. SUB ShowMemory(title$) STATIC
  181. '•Version 0.40 by Ray DiBugnara, Bolton, MA
  182. '•Title$=short string to be displayed on first line of display
  183. '  If option key is held down while call is made to ShowMemory, it does.
  184.     IF (PEEK(379)<>4 AND PEEK(379)<>6) THEN EXIT SUB  'looking for option key
  185.     POKE &HBF4,1  'turn on/off fractional widths.
  186.     WINDOW 7,"Memory Map",(100,80)-(405,305),-5
  187. RefreshSM:
  188.     POKE &HBF4,1  'turn on/off fractional widths.
  189.     TEXTFONT 3 : TEXTSIZE 10 : TEXTFACE 1 : CLS
  190.     w%=0 : CALL TextWidth(title$,w%) : x%=(305-w%)/2-10 : y%=12
  191.     CALL MOVETO(x%,y%)
  192.     PRINT "   ";title$
  193.     TEXTFACE 0 : TEXTSIZE 9
  194.     currentA5#=PEEKL(&H904)
  195.     applTop#=currentA5#+144+32 : PRINT "   applTop# (Top of Application Space) =";applTop#
  196.     curStackBase#=PEEKL(&H908) : PRINT "   curStackBase# (Top of Stack) =";curStackBase#
  197.     applLimit#=PEEKL(&H130) : PRINT "   applLimit# (Top of Application Limit Space) =";applLimit#
  198.     heapEnd#=PEEKL(&H114) : PRINT "   heapEnd# (Top of Application Heap) =";heapEnd#
  199.     applZone#=PEEKL(&H2AA) : PRINT "   applZone# (Bottom of Application Space) =";applZone#
  200.     PRINT
  201.     PRINT "   Total Application Space (applTop#-applZone#) =";applTop#-applZone#
  202.     PRINT "   Total Globals+Stack (applTop#-applLimit#) =";applTop#-applLimit#
  203.     PRINT "   Total Stack Space (curStackBase#-applLimit#) =";curStackBase#-applLimit#
  204.     PRINT
  205.     PRINT "   Unused Application Heap (applLimit#-heapEnd#) =";applLimit#-heapEnd#
  206.     PRINT "   Used Application Heap (heapEnd#-applZone#) =";heapEnd#-applZone#
  207.     PRINT "   Total Application Heap (applLimit#-applZone#) =";applLimit#-applZone#
  208.     PRINT
  209.     unusedData#=FRE(0) : PRINT "   FRE(-0) Unused bytes in data segment =";unusedData#
  210.     unusedHeap#=FRE(-1) : PRINT "   FRE(-1) Unused bytes in application Heap =";unusedHeap#
  211.     unusedStack#=FRE(-2) : PRINT "   FRE(-2) Unused Stack bytes =";unusedStack#;
  212. LoopSM:    
  213.     FOR n%=1 TO 10 : d%=DIALOG(0) : m%=MOUSE(0) : NEXT n%
  214.     a$="q" : WHILE a$<>"" : a$=INKEY$: WEND
  215.     WHILE a$="" AND d%=0 AND m%=0
  216.         a$=INKEY$ : d%=DIALOG(0) : m%=MOUSE(0)
  217.     WEND   'press anything to continue
  218.     WHILE a$<>"" : a$=INKEY$ : WEND  'clear buffer before exiting
  219.     IF d%=5 THEN w%=DIALOG(5)
  220.     IF d%=5 AND w%=7 THEN GOTO RefreshSM
  221.     IF d%=5  AND w%<>7 THEN GOTO LoopSM
  222.     WINDOW CLOSE 7
  223. END SUB  'ShowMemory
  224.  
  225.  
  226. Good Luck!  Ray DiBugnara
  227.