Memory usage monitor

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:



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:


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