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:
- 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 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