by Richard Russell, May 2007

This facility is now more conveniently available as an Add-In Utility

It is sometimes useful to be able to monitor memory usage (for example heap and stack size) while a program is running. This can alert you to problems like a memory leak (increasing and irreversible use of memory, eventually resulting in a 'No room' error) or wasteful use of memory resources (e.g. excessive string garbage).

Whilst you can always add your own code to monitor and report memory usage, it can be inconvenient and awkward to do so without disrupting your program's normal operation. This article lists a short routine which you can include in any program, which reports memory usage in a separate window:

monitor.gif

The routine can most easily be activated by means of an ON TIME interrupt, allowing it to run whatever your program is doing (within reason) and with the minimum need for modification to your program. Simply add the following statement near the beginning of your program:

      ON TIME PROCmonitor : RETURN
This assumes you don't already have an ON TIME interrupt; if you do, add PROCmonitor to the code executed in the interrupt routine.

The values reported by PROCmonitor are as follows:

  • Total heap usage: the amount of memory being used to store your program's global variables, arrays, structures, string free space and memory allocated using DIM.
  • Total stack usage: the amount of memory being used to store your program's LOCAL variables, arrays, structures, memory allocated using DIM LOCAL and looping/nesting structures.
  • Total library usage: the amount of memory above HIMEM being used for INSTALLed libraries.
  • String free space: the amount of memory freed by deallocating or re-sizing strings, and available for string storage.
  • Free heap/stack: the amount of memory available for growth of the heap and stack (without needing to increase the value of HIMEM).

In each case the memory size is given in bytes. Note that in normal circumstances heap usage will never decrease (there are exceptions such as use of the CLEAR statement, or deallocating a string at the top of the heap) but stack usage will increase and decrease, often by a considerable amount.

The PROCmonitor routine is listed below. Note that it automatically loads the WINLIB2 library if required, but doesn't do so if it is already installed:

      DEF PROCmonitor
      PRIVATE D%, L%
      IF L% THEN ENDPROC
      L% = TRUE
      IF D%=0 THEN
        ON ERROR LOCAL RESTORE ERROR : INSTALL @lib$+"WINLIB2"
        D%=FN_newdialog("Memory usage monitor",50,50,149,102,8,570)
        D%!20 += 8
        PROC_static(D%,"Total heap usage:",100,12,10,64,16,0)
        PROC_editbox(D%,"",101,79,9,56,12,&800)
        PROC_static(D%,"Total stack usage:",102,12,28,64,16,0)
        PROC_editbox(D%,"",103,79,27,56,12,&800)
        PROC_static(D%,"Total library usage:",104,12,46,64,16,0)
        PROC_editbox(D%,"",105,79,45,56,12,&800)
        PROC_static(D%,"String free space:",106,12,64,64,16,0)
        PROC_editbox(D%,"",107,79,63,56,12,&800)
        PROC_static(D%,"Free heap/stack:",108,12,82,64,16,0)
        PROC_editbox(D%,"",109,79,81,56,12,&800)
        PROC_showdialog(D%)
      ENDIF
      LOCAL B%, I%, P%, S%
      DIM S% LOCAL -1
      SYS "SetDlgItemInt", !D%, 101, END-LOMEM
      SYS "SetDlgItemInt", !D%, 103, HIMEM-S%
      SYS "SetDlgItemInt", !D%, 109, S%-END-512
      P% = !360
      IF P% THEN WHILE ?P% : P% += ?P% : ENDWHILE : P% = P%+4-!360
      SYS "SetDlgItemInt", !D%, 105, P%
      B% = 0
      FOR I% = 0 TO 16
        P% = @vdu%+512+4*I%
        WHILE !P%
          P% = !P%
          B% += (1<<I%)-1
        ENDWHILE
      NEXT
      SYS "SetDlgItemInt", !D%, 107, B%
      L% = FALSE
      ENDPROC