Chapter 6: The Demonstration Programs Source code for about a dozen demonstration programs is provided in the subdirectory \DEMO_SRC on the library disk. [On the demonstration disk only seven demonstration programs may be found, since executable programs are also provided.] The header file L_MEM.H is necessary for compilation of these programs. The demonstration programs can be compiled with both the Microsoft C compiler and the Borland/Turbo C++ compilers. See Sections (c) and (d) of Chapter 3 of this manual regarding procedures for linking Dolphin library functions with programs compiled using these compilers. Some of these programs take command line parameters, as explained in the following sections. Some of them output one or more memory allocation log reports; these are usually reproduced in the appropriate sections below. (a) The TINYBUG.C program The TINYBUG.C program shows how the memory allocation log can be used to reveal a bug. The program is as follows: /* TINYBUG.C */ #include #include Far_ptr ptr[1000]; char *usage = "\nUse TINYBUG to run without the memory log" "\n or TINYBUG 1 to run with the memory log.\n" "\nThis program allocates %lu-byte blocks and frees them."; /*---------------------------*/ void main(int argc,char **argv) { int i, err_flag, num_blocks; Ulong block_size=2000L; int log=FALSE; printf(usage,block_size); if ( argc > 1 ) Ú{ ³log = TRUE; ³printf("\nA summary log report is then displayed, " ³ "and the log is erased.\n"); À} printf("\nLargest available block: %lu bytes.", mem_max(&err_flag)); if ( log ) set_mem_log(TRUE); /* allocate memory blocks until insufficient memory */ printf("\nNow allocating blocks ... "); num_blocks = 0; i = 0; while ( TRUE ) Ú{ ³ptr[i++] = mem_alloc(block_size,&err_flag); ³if ( err_flag ) /* if error */ ³ break; /* exit loop */ ³else /* else */ ³ num_blocks++; /* increment block count */ À} printf(" %d blocks allocated.",num_blocks); /* now free the blocks */ printf("\nNow freeing blocks ... "); /* decrement i to compensate for NULL pointer * returned by last mem_alloc() */ i--; while ( num_blocks-- > 0 ) Ú{ ³mem_free(ptr[i--],&err_flag); ³if ( err_flag == BLOCK_ALREADY_FREED ) ³ Ú{ ³ ³printf("\nBlock already freed."); ³ ³return; ³ À} À} printf("done."); if ( log ) Ú{ ³printf("\nNow producing report #3:"); ³mem_log_report(3,stdout,0,FALSE,&err_flag); ³printf("\nNow erasing log ... "); ³mem_erase_log(&err_flag); ³printf("done."); À} printf("\nLargest available block: %lu bytes.\n",mem_max(&err_flag)); } The program allocates 2000-byte blocks of memory until no more can be allocated, and then frees the blocks. When TINYBUG is run with no command line parameter, so that the log is not used, the screen output is as follows: Use TINYBUG to run without the memory log or TINYBUG 1 to run with the memory log. This program allocates 2000-byte blocks and frees them. Largest available block: 486880 bytes. Now allocating blocks ... 241 blocks allocated. Now freeing blocks ... done. Largest available block: 484864 bytes. The program runs OK, and there would be no reason to suppose a bug was lurking except that one might expect that the two values for the largest available memory block, before and after the allocations and frees, would be the same, whereas they differ by 2016 bytes. When TINYBUG is run with command line parameter 1, so that the log is used, the screen output is as follows: This program allocates 2000-byte blocks and frees them. A summary log report is then displayed, and the log is erased. Largest available block: 486880 bytes. Now allocating blocks ... 235 blocks allocated. Now freeing blocks ... done. Now producing report #3: Number of entries in the memory allocation log: 471 235 memory blocks (or arrays) were allocated. 234 blocks (or arrays) were freed. 1 block (or array) was not freed. 1 memory operation had insufficient memory. 1 null pointer passed. Now erasing log ... done. Largest available block: 484864 bytes. The summary log report tells us immediately that one of the allocated blocks was not freed. Thus we know there is a bug in the following code: /* decrement i to compensate for NULL pointer * returned by last mem_alloc() */ i--; while ( num_blocks-- > 0 ) mem_free(ptr[i--],&err_flag); Interested readers may care to identify the bug. The answer is given at the end of this chapter, following Section (n). (b) The LOG_DEMO.C program. 1: /* LOG_DEMO.C 2: * demonstration of the use of the memory allocation log 3: * last mod.: 2-JUN-91 4: */ 5: 6: #include 7: #include 8: #include 9: #include 10: #include 11: #include 12: 13: char msg[72]; 14: 15: /*-----------*/ 16: void main(void) 17: { 18: Far_ptr ptr; 19: int err_flag, ch; 20: char *logfile = "LOG_DEMO.LOG"; 21: FILE *output; 22: 23: set_mem_log(TRUE); 24: set_termination_log_output(PRINTER_OUTPUT,REPORT_1_ONLY); 25: 26: while ( kbhit() ) 27: ; 28: printf("\nThis program prints log reports #1 and #2." 29: "\nSend to printer or to disk? (P/D) "); 30: ch = 0; 31: while ( ! ( ch == 'P' || ch == 'D' ) ) 32: Ú{ 33: ³ch = getch(); 34: ³if ( ch > 'Z' ) 35: ³ ch -= 32; 36: À} 37: putch(ch); 38: 39: _L_(mem_max(&err_flag);) /* write in log */ 40: if ( !err_flag ) /* if no error */ 41: Ú{ 42: ³/* allocate 1000 bytes */ 43: ³_L_(ptr = mem_alloc(1000L,&err_flag);) 44: ³if ( !err_flag ) 45: ³ Ú{ 46: ³ ³/* allocate 69632 bytes and set to '2' */ 47: ³ ³_L_(mem_alloc_ch(0x11000,'2',&err_flag);) 48: ³ ³if ( !err_flag ) 49: ³ ³ Ú{ 50: ³ ³ ³/* increase first block by 2000 bytes */ 51: ³ ³ ³_L_(ptr = mem_increase(ptr,2000,TRUE,&err_flag);) 52: ³ ³ ³if ( !err_flag ) 53: ³ ³ ³ Ú{ 54: ³ ³ ³ ³/* set bytes of first block to '1' */ 55: ³ ³ ³ ³_L_(mem_set(ptr,'1',&err_flag);) 56: ³ ³ ³ À} 57: ³ ³ À} 58: ³ À} 59: À} 60: 61: /* free all allocated memory blocks */ 62: _L_(mem_free_all(0,&err_flag);) 63: 64: if ( ch == 'P' ) 65: Ú{ 66: ³printf("\nNow printing reports ..."); 67: ³mem_log_report(1,stdprn,1,FALSE,&err_flag); 68: ³if ( !err_flag ) /* if no error */ 69: ³ mem_log_report(2,stdprn,1,TRUE,&err_flag); 70: À} 71: else /* send reports to disk file LOG */ 72: Ú{ 73: ³printf("\nNow writing reports to file %s ...",logfile); 74: ³if ( ( output = fopen(logfile,"wt") ) == NULL ) 75: ³ printf("\nUnable to open file %s.",logfile); 76: ³else 77: ³ Ú{ 78: ³ ³mem_log_report(1,output,1,FALSE,&err_flag); 79: ³ ³if ( !err_flag ) 80: ³ ³ mem_log_report(2,output,1,TRUE,&err_flag); 81: ³ À} 82: À} 83: 84: if ( err_flag ) 85: Ú{ 86: ³printf("\nAn error occurred: %s", mem_err_msg(err_flag,msg)); 87: ³exit(1); 88: À} 89: 90: printf("\n"); 91: } This program produces two different reports based on the memory allocation log. The first is a chronological record of memory operations, something like the following (the numbers in square brackets are program line numbers): Number of entries in the memory allocation log: 9 1 [39] "Ascertain maximum available." 470736 bytes. 2 [43] "Allocate 1000 bytes." 63 (0x3F) paragraphs (1008 bytes) allocated at 2D0A:0000. Address of first byte beyond block is 2D49:0000. 3 [47] "Allocate 69632 bytes." 4352 (0x1100) paragraphs (69632 bytes) allocated at 2D4A:0000. Address of first byte beyond block is 3E4A:0000. 4 [51] "Increase 2D0A:0000 by 2000 bytes (from 1008 bytes)." 188 (0xBC) paragraphs (3008 bytes) allocated at 3E4B:0000. Address of first byte beyond block is 3F07:0000. 5 [55] "Set block at 3E4B:0000 (3008 bytes). Done. Address of first byte beyond block is 3F07:0000. 6 [62] Message: About to free all allocated blocks/arrays. 7 [62] "Free block at 3E4B:0000." 3008 bytes (0xBC paragraphs) freed. Address of first byte beyond block is 3F07:0000. 8 [62] "Free block at 2D4A:0000." 69632 bytes (0x1100 paragraphs) freed. Address of first byte beyond block is 3E4A:0000. 9 [62] "Free all blocks/arrays." 2 freed. Number of entries in the memory allocation log: 9 *** Block/array ID = 1 *** 2 [43] "Allocate 1000 bytes." 63 (0x3F) paragraphs (1008 bytes) allocated at 2D0A:0000. Address of first byte beyond block is 2D49:0000. 4 [51] "Increase 2D0A:0000 by 2000 bytes (from 1008 bytes)." 188 (0xBC) paragraphs (3008 bytes) allocated at 3E4B:0000. Address of first byte beyond block is 3F07:0000. 5 [55] "Set block at 3E4B:0000 (3008 bytes). Done. Address of first byte beyond block is 3F07:0000. 7 [62] "Free block at 3E4B:0000." 3008 bytes (0xBC paragraphs) freed. Address of first byte beyond block is 3F07:0000. *** Block/array ID = 2 *** 3 [47] "Allocate 69632 bytes." 4352 (0x1100) paragraphs (69632 bytes) allocated at 2D4A:0000. Address of first byte beyond block is 3E4A:0000. 8 [62] "Free block at 2D4A:0000." 69632 bytes (0x1100 paragraphs) freed. Address of first byte beyond block is 3E4A:0000. 2 memory blocks (or arrays) were allocated. 2 memory blocks (or arrays) were freed. (c) The FMALLBUG.C program FMALLBUG.C and FRAG.C (given below in Section (g)) demonstrate that Microsoft's far memory allocation function _fmalloc() (to which malloc() maps in the medium and large models) has problems. Specifically, it causes excessive heap fragmentation, leading to occasional failure despite the presence of lots of free memory in the far heap. These two programs also demonstrate that mem_alloc(), the Dolphin replacement for _fmalloc(), does not have this problem. FMALLBUG.C is intended for compilation only with Microsoft C. 1: /* FMALLBUG.C 2: * this program reveals a problem with Microsoft's 3: * far memory allocation function, _fmalloc() 4: * last mod.: 2-JUN-91 5: */ 6: 7: #include 8: #include 9: #include 10: #include 11: #include 12: #include 13: #include 14: 15: #include 16: 17: typedef struct mb 18: Ú{ 19: ³struct mb far *mb_previous; 20: ³int mb_data; 21: À} Mem_block; 22: 23: Mem_block far *list; 24: Mem_block far *p; 25: Uint first_alloc_size = 40000; 26: Uint second_alloc_size = 46000; 27: Ulong first_allocation, second_allocation; 28: int err_flag, ch; 29: char msg[81]; 30: 31: void main(int argc, char **argv); 32: void display_first_allocation(void); 33: void display_second_allocation(void); 34: Ulong msc_allocation(Uint block_size); 35: Ulong dolphin_allocation(Uint block_size, int *err_flag); 36: void compact_mem_log(void); 37: void print_reports(void); 38: 39: /*---------------------------*/ 40: void main(int argc,char **argv) 41: { 42: set_mem_alloc_strategy(atoi(argv[1])); 43: 44: printf("\n\nmem_alloc() without memory log " 45: "(max. avail.: %lu bytes):",mem_max(&err_flag)); 46: first_allocation = dolphin_allocation(first_alloc_size,&err_flag); 47: display_first_allocation(); 48: second_allocation = dolphin_allocation(second_alloc_size,&err_flag); 49: display_second_allocation(); 50: 51: set_mem_log(TRUE); 52: /* write program name to log */ 53: strcpy(msg,"Program is "); 54: strcat(msg,argv[0]); 55: _L_(mem_log_msg(msg,&err_flag);) 56: 57: printf("\n\nmem_alloc() with memory log (max. avail.: %lu bytes):", 58: mem_max(&err_flag)); 59: first_allocation = dolphin_allocation(first_alloc_size,&err_flag); 60: display_first_allocation(); 61: second_allocation = dolphin_allocation(second_alloc_size,&err_flag); 62: display_second_allocation(); 63: printf("\n"); 64: 65: compact_mem_log(); 66: sprintf(msg,"mem_alloc() with memory log and compaction " 67: "(max. avail.: %lu bytes)",mem_max(&err_flag)); 68: printf("\n%s:",msg); 69: /* put the message in the memory log */ 70: _L_(mem_log_msg(msg,&err_flag);) 71: first_allocation = dolphin_allocation(first_alloc_size,&err_flag); 72: display_first_allocation(); 73: compact_mem_log(); 74: second_allocation = dolphin_allocation(second_alloc_size,&err_flag); 75: display_second_allocation(); 76: printf("\n"); 77: 78: /* can't do this at the beginning because _fmalloc() 79: * ties up memory and so mem_alloc() does not succeed 80: */ 81: compact_mem_log(); 82: printf("\nUsing _fmalloc() (max. available: %lu bytes):", 83: mem_max(&err_flag)); 84: first_allocation = msc_allocation(first_alloc_size); 85: display_first_allocation(); 86: second_allocation = msc_allocation(second_alloc_size); 87: display_second_allocation(); 88: print_reports(); 89: } 90: 91: /*-------------------------------*/ 92: void display_first_allocation(void) 93: { 94: Uint num_blocks = (Uint)(first_allocation/first_alloc_size); 95: 96: printf("\nUsing block size %u, %lu bytes allocated (%u block%s)%s.", 97: first_alloc_size,first_allocation,num_blocks, 98: ( num_blocks==1 ? "" : "s" ), 99: ( num_blocks==0 ? "" : " and freed" ) ); 100: } 101: 102: /*--------------------------------*/ 103: void display_second_allocation(void) 104: { 105: Uint num_blocks = (Uint)(second_allocation/second_alloc_size); 106: 107: printf("\nUsing block size %u, %lu bytes allocated (%u block%s)%s.", 108: second_alloc_size,second_allocation,num_blocks, 109: ( num_blocks==1 ? "" : "s" ), 110: ( num_blocks==0 ? "" : " and freed" ) ); 111: } 112: 113: /*---------------------------------*/ 114: Ulong msc_allocation(Uint block_size) 115: { 116: Ulong total_allocation = 0L; 117: 118: list = (Mem_block far *)NULL; 119: 120: /* allocate memory blocks until memory exhausted */ 121: while ( ( p = (Mem_block far *)_fmalloc(block_size) ) 122: != (Mem_block far *)NULL ) 123: Ú{ 124: ³p->mb_previous = list; 125: ³list = p; 126: ³total_allocation += block_size; 127: À} 128: 129: /* free the allocated blocks */ 130: while ( list != (Mem_block far *)NULL ) 131: Ú{ 132: ³p = list; 133: ³list = list->mb_previous; 134: ³_ffree(p); 135: À} 136: 137: return ( total_allocation ); 138: } 139: 140: /*---------------------------------------------------*/ 141: Ulong dolphin_allocation(Uint block_size,int *err_flag) 142: { 143: Ulong total_allocation = 0L; 144: 145: list = (Mem_block far *)NULL; 146: *err_flag = NO_ERROR; 147: 148: /* allocate memory blocks until memory exhausted */ 149: while ( TRUE ) 150: Ú{ 151: ³_L_(p = (Mem_block far *)mem_alloc((Ulong)block_size,err_flag);) 152: ³if ( *err_flag ) 153: ³ break; 154: ³p->mb_previous = list; 155: ³list = p; 156: ³total_allocation += block_size; 157: À} 158: 159: if ( *err_flag == INSUFFICIENT_MEMORY ) 160: *err_flag = NO_ERROR; 161: 162: if ( *err_flag ) 163: Ú{ 164: ³printf("\n%s",mem_err_msg(*err_flag,msg)); 165: ³exit(1); 166: À} 167: else 168: Ú{ 169: ³/* free the allocated blocks */ 170: ³while ( TRUE ) 171: ³ Ú{ 172: ³ ³p = list; 173: ³ ³list = list->mb_previous; 174: ³ ³_L_(mem_free((Far_str_ptr)p,err_flag);) 175: ³ ³if ( *err_flag == NULL_POINTER ) 176: ³ ³ break; 177: ³ ³else if ( *err_flag != NO_ERROR ) 178: ³ ³ Ú{ 179: ³ ³ ³printf("\n%s",mem_err_msg(*err_flag,msg)); 180: ³ ³ ³exit(2); 181: ³ ³ À} 182: ³ À} 183: À} 184: 185: return ( total_allocation ); 186: } 187: 188: /*----------------------*/ 189: void compact_mem_log(void) 190: { 191: _L_(compact_log(&err_flag);) 192: if ( err_flag ) 193: Ú{ 194: ³printf("\nError when compacting log: %s",mem_err_msg(err_flag,msg)); 195: ³mem_log_msg("Error when compacting log.",&err_flag); 196: À} 197: else 198: Ú{ 199: ³printf("\nMemory log compacted."); 200: ³_L_(mem_log_msg("Memory log compacted.",&err_flag);) 201: À} 202: } 203: 204: /*--------------------*/ 205: void print_reports(void) 206: { 207: FILE *output; 208: char *logfile = "FMALLBUG.LOG"; 209: 210: printf("\n\nMemory allocation log has %u entries.",mem_log_entries()); 211: printf("\nPress P to send reports #1 and #2 to printer," 212: "\nF to send reports to disk file %s," 213: "\nany other key to quit ... ",logfile); 214: 215: while ( kbhit() ) 216: getch(); 217: ch = getche(); 218: if ( ch == 'P' || ch == 'p' ) 219: Ú{ 220: ³setmode(fileno(stdprn),O_TEXT); 221: ³mem_log_report(1,stdprn,1,TRUE,&err_flag); 222: ³mem_log_report(2,stdprn,1,TRUE,&err_flag); 223: À} 224: else if ( ch == 'F' || ch == 'f' ) 225: Ú{ 226: ³if ( ( output = fopen(logfile,"wt") ) == NULL ) 227: ³ Ú{ 228: ³ ³printf("\nUnable to open file %s",logfile); 229: ³ ³exit(1); 230: ³ À} 231: ³mem_log_report(1,output,1,TRUE,&err_flag); 232: ³if ( err_flag ) 233: ³ printf("\nError when writing first report: %s", 234: ³ mem_err_msg(err_flag,msg)); 235: ³else 236: ³ Ú{ 237: ³ ³mem_log_report(2,output,1,TRUE,&err_flag); 238: ³ ³if ( err_flag ) 239: ³ ³ printf("\nError when writing second report: %s", 240: ³ ³ mem_err_msg(err_flag,msg)); 241: ³ À} 242: À} 243: 244: printf("\n"); 245: } This program demonstrates an unreliable aspect of Microsoft's _fmalloc() function. If a set of memory blocks, in this case 40,000-byte blocks, are allocated with _fmalloc() and then freed, there should be enough free memory to allocate another set of 46,000-byte blocks. In fact _fmalloc() will be able to allocate at most two such blocks, despite the fact that most of the far heap is free. FMALLBUG.C demonstrates this, in the latter part of the program. The earlier part of the program shows that mem_alloc() does not have this problem. A typical screen output will begin thus: mem_alloc() without memory log (max. avail.: 483520 bytes): Using block size 40000, 480000 bytes allocated (12 blocks) and freed. Using block size 46000, 460000 bytes allocated (10 blocks) and freed. However, when the memory log is turned on (at line 51) the problem reappears: mem_alloc() with memory log (max. avail.: 483280 bytes): Using block size 40000, 480000 bytes allocated (12 blocks) and freed. Using block size 46000, 0 bytes allocated (0 blocks). This is because each log entry is a 32-byte block in the far heap, and these occur between the 40,000-byte blocks. When the 40,000-byte blocks are freed, the log entries are scattered among free blocks, preventing allocation of a 46,000-byte block. The problem may be overcome by using compact_log() (which is used at line 191 in the compact_mem_log() function in FMALLBUG.C). This takes the log entries, scattered about the far heap, and consolidates them into one contiguous part of memory. With compaction we obtain: Memory log compacted. mem_alloc() with memory log and compaction (max. avail.: 481648 bytes): Using block size 40000, 480000 bytes allocated (12 blocks) and freed. Memory log compacted. Using block size 46000, 460000 bytes allocated (10 blocks) and freed. Finally _fmalloc() is used (it could not be used before the experiments with mem_alloc() because the far heap fragmentation caused by _fmalloc() would prevent mem_alloc() from allocating memory properly). With _fmalloc() we have: Memory log compacted. Using _fmalloc() (max. available: 475312 bytes): Using block size 40000, 440000 bytes allocated (11 blocks) and freed. Using block size 46000, 46000 bytes allocated (1 block) and freed. Even though all eleven blocks allocated using _fmalloc() were freed, thus freeing a total of 440,000 bytes, _fmalloc() can only find space to allocate a single 46,000-byte block. The FMALLBUG program gives you the option of sending the memory allocation log to printer or to disk file. The log should look something like the following (numbers in square backets are program line numbers): Number of entries in the memory allocation log: 80 1 [55] Message: Program is E:\MEMLIB\DISKS\DEMO\DEMO_SRC\FMALLBUG.EXE 2 "Ascertain maximum available." 476560 bytes. 3 [151] "Allocate 40000 bytes." 2500 (0x9C4) paragraphs (40000 bytes) allocated at 2B9E:0000. Address of first byte beyond block is 3562:0000. 4 [151] "Allocate 40000 bytes." 2500 (0x9C4) paragraphs (40000 bytes) allocated at 3563:0000. Address of first byte beyond block is 3F27:0000. 5 [151] "Allocate 40000 bytes." 2500 (0x9C4) paragraphs (40000 bytes) allocated at 3F28:0000. Address of first byte beyond block is 48EC:0000. 6 [151] "Allocate 40000 bytes." 2500 (0x9C4) paragraphs (40000 bytes) allocated at 48ED:0000. Address of first byte beyond block is 52B1:0000. 7 [151] "Allocate 40000 bytes." 2500 (0x9C4) paragraphs (40000 bytes) allocated at 52B2:0000. Address of first byte beyond block is 5C76:0000. 8 [151] "Allocate 40000 bytes." 2500 (0x9C4) paragraphs (40000 bytes) allocated at 5C7A:0000. Address of first byte beyond block is 663E:0000. 9 [151] "Allocate 40000 bytes." 2500 (0x9C4) paragraphs (40000 bytes) allocated at 6642:0000. Address of first byte beyond block is 7006:0000. 10 [151] "Allocate 40000 bytes." 2500 (0x9C4) paragraphs (40000 bytes) allocated at 700A:0000. Address of first byte beyond block is 79CE:0000. 11 [151] "Allocate 40000 bytes." 2500 (0x9C4) paragraphs (40000 bytes) allocated at 79D2:0000. Address of first byte beyond block is 8396:0000. 12 [151] "Allocate 40000 bytes." 2500 (0x9C4) paragraphs (40000 bytes) allocated at 839A:0000. Address of first byte beyond block is 8D5E:0000. 13 [151] "Allocate 40000 bytes." 2500 (0x9C4) paragraphs (40000 bytes) allocated at 8D62:0000. Address of first byte beyond block is 9726:0000. 14 [151] "Allocate 40000 bytes." Error: insufficient memory Maximum available is 36048 bytes. 15 [174] "Free block at 8D62:0000." 40000 bytes (0x9C4 paragraphs) freed. Address of first byte beyond block is 9726:0000. 16 [174] "Free block at 839A:0000." 40000 bytes (0x9C4 paragraphs) freed. Address of first byte beyond block is 8D5E:0000. 17 [174] "Free block at 79D2:0000." 40000 bytes (0x9C4 paragraphs) freed. Address of first byte beyond block is 8396:0000. 18 [174] "Free block at 700A:0000." 40000 bytes (0x9C4 paragraphs) freed. Address of first byte beyond block is 79CE:0000. 19 [174] "Free block at 6642:0000." 40000 bytes (0x9C4 paragraphs) freed. Address of first byte beyond block is 7006:0000. 20 [174] "Free block at 5C7A:0000." 40000 bytes (0x9C4 paragraphs) freed. Address of first byte beyond block is 663E:0000. 21 [174] "Free block at 52B2:0000." 40000 bytes (0x9C4 paragraphs) freed. Address of first byte beyond block is 5C76:0000. 22 [174] "Free block at 48ED:0000." 40000 bytes (0x9C4 paragraphs) freed. Address of first byte beyond block is 52B1:0000. 23 [174] "Free block at 3F28:0000." 40000 bytes (0x9C4 paragraphs) freed. Address of first byte beyond block is 48EC:0000. 24 [174] "Free block at 3563:0000." 40000 bytes (0x9C4 paragraphs) freed. Address of first byte beyond block is 3F27:0000. 25 [174] "Free block at 2B9E:0000." 40000 bytes (0x9C4 paragraphs) freed. Address of first byte beyond block is 3562:0000. 26 [174] "Free block at 0:0000." Error: null pointer 27 [151] "Allocate 46000 bytes." Error: insufficient memory Maximum available is 39808 bytes. 28 [174] "Free block at 0:0000." Error: null pointer 29 [200] Message: Memory log compacted. 30 "Ascertain maximum available." 475072 bytes. 31 [70] Message: mem_alloc() with memory log and compaction (max. avail.: 475072 bytes) 32 [151] "Allocate 40000 bytes." 2500 (0x9C4) paragraphs (40000 bytes) allocated at 2BFB:0000. Address of first byte beyond block is 35BF:0000. 33 [151] "Allocate 40000 bytes." 2500 (0x9C4) paragraphs (40000 bytes) allocated at 35C0:0000. Address of first byte beyond block is 3F84:0000. 34 [151] "Allocate 40000 bytes." 2500 (0x9C4) paragraphs (40000 bytes) allocated at 3F85:0000. Address of first byte beyond block is 4949:0000. 35 [151] "Allocate 40000 bytes." 2500 (0x9C4) paragraphs (40000 bytes) allocated at 494A:0000. Address of first byte beyond block is 530E:0000. 36 [151] "Allocate 40000 bytes." 2500 (0x9C4) paragraphs (40000 bytes) allocated at 5312:0000. Address of first byte beyond block is 5CD6:0000. 37 [151] "Allocate 40000 bytes." 2500 (0x9C4) paragraphs (40000 bytes) allocated at 5CDA:0000. Address of first byte beyond block is 669E:0000. 38 [151] "Allocate 40000 bytes." 2500 (0x9C4) paragraphs (40000 bytes) allocated at 66A2:0000. Address of first byte beyond block is 7066:0000. 39 [151] "Allocate 40000 bytes." 2500 (0x9C4) paragraphs (40000 bytes) allocated at 706A:0000. Address of first byte beyond block is 7A2E:0000. 40 [151] "Allocate 40000 bytes." 2500 (0x9C4) paragraphs (40000 bytes) allocated at 7A32:0000. Address of first byte beyond block is 83F6:0000. 41 [151] "Allocate 40000 bytes." 2500 (0x9C4) paragraphs (40000 bytes) allocated at 83FA:0000. Address of first byte beyond block is 8DBE:0000. 42 [151] "Allocate 40000 bytes." 2500 (0x9C4) paragraphs (40000 bytes) allocated at 8DC2:0000. Address of first byte beyond block is 9786:0000. 43 [151] "Allocate 40000 bytes." Error: insufficient memory Maximum available is 34512 bytes. 44 [174] "Free block at 8DC2:0000." 40000 bytes (0x9C4 paragraphs) freed. Address of first byte beyond block is 9786:0000. 45 [174] "Free block at 83FA:0000." 40000 bytes (0x9C4 paragraphs) freed. Address of first byte beyond block is 8DBE:0000. 46 [174] "Free block at 7A32:0000." 40000 bytes (0x9C4 paragraphs) freed. Address of first byte beyond block is 83F6:0000. 47 [174] "Free block at 706A:0000." 40000 bytes (0x9C4 paragraphs) freed. Address of first byte beyond block is 7A2E:0000. 48 [174] "Free block at 66A2:0000." 40000 bytes (0x9C4 paragraphs) freed. Address of first byte beyond block is 7066:0000. 49 [174] "Free block at 5CDA:0000." 40000 bytes (0x9C4 paragraphs) freed. Address of first byte beyond block is 669E:0000. 50 [174] "Free block at 5312:0000." 40000 bytes (0x9C4 paragraphs) freed. Address of first byte beyond block is 5CD6:0000. 51 [174] "Free block at 494A:0000." 40000 bytes (0x9C4 paragraphs) freed. Address of first byte beyond block is 530E:0000. 52 [174] "Free block at 3F85:0000." 40000 bytes (0x9C4 paragraphs) freed. Address of first byte beyond block is 4949:0000. 53 [174] "Free block at 35C0:0000." 40000 bytes (0x9C4 paragraphs) freed. Address of first byte beyond block is 3F84:0000. 54 [174] "Free block at 2BFB:0000." 40000 bytes (0x9C4 paragraphs) freed. Address of first byte beyond block is 35BF:0000. 55 [174] "Free block at 0:0000." Error: null pointer 56 [200] Message: Memory log compacted. 57 [151] "Allocate 46000 bytes." 2875 (0xB3B) paragraphs (46000 bytes) allocated at 2CA3:0000. Address of first byte beyond block is 37DE:0000. 58 [151] "Allocate 46000 bytes." 2875 (0xB3B) paragraphs (46000 bytes) allocated at 37DF:0000. Address of first byte beyond block is 431A:0000. 59 [151] "Allocate 46000 bytes." 2875 (0xB3B) paragraphs (46000 bytes) allocated at 431B:0000. Address of first byte beyond block is 4E56:0000. 60 [151] "Allocate 46000 bytes." 2875 (0xB3B) paragraphs (46000 bytes) allocated at 4E57:0000. Address of first byte beyond block is 5992:0000. 61 [151] "Allocate 46000 bytes." 2875 (0xB3B) paragraphs (46000 bytes) allocated at 5993:0000. Address of first byte beyond block is 64CE:0000. 62 [151] "Allocate 46000 bytes." 2875 (0xB3B) paragraphs (46000 bytes) allocated at 64CF:0000. Address of first byte beyond block is 700A:0000. 63 [151] "Allocate 46000 bytes." 2875 (0xB3B) paragraphs (46000 bytes) allocated at 700B:0000. Address of first byte beyond block is 7B46:0000. 64 [151] "Allocate 46000 bytes." 2875 (0xB3B) paragraphs (46000 bytes) allocated at 7B47:0000. Address of first byte beyond block is 8682:0000. 65 [151] "Allocate 46000 bytes." 2875 (0xB3B) paragraphs (46000 bytes) allocated at 8683:0000. Address of first byte beyond block is 91BE:0000. 66 [151] "Allocate 46000 bytes." 2875 (0xB3B) paragraphs (46000 bytes) allocated at 91BF:0000. Address of first byte beyond block is 9CFA:0000. 67 [151] "Allocate 46000 bytes." Error: insufficient memory Maximum available is 12224 bytes. 68 [174] "Free block at 91BF:0000." 46000 bytes (0xB3B paragraphs) freed. Address of first byte beyond block is 9CFA:0000. 69 [174] "Free block at 8683:0000." 46000 bytes (0xB3B paragraphs) freed. Address of first byte beyond block is 91BE:0000. 70 [174] "Free block at 7B47:0000." 46000 bytes (0xB3B paragraphs) freed. Address of first byte beyond block is 8682:0000. 71 [174] "Free block at 700B:0000." 46000 bytes (0xB3B paragraphs) freed. Address of first byte beyond block is 7B46:0000. 72 [174] "Free block at 64CF:0000." 46000 bytes (0xB3B paragraphs) freed. Address of first byte beyond block is 700A:0000. 73 [174] "Free block at 5993:0000." 46000 bytes (0xB3B paragraphs) freed. Address of first byte beyond block is 64CE:0000. 74 [174] "Free block at 4E57:0000." 46000 bytes (0xB3B paragraphs) freed. Address of first byte beyond block is 5992:0000. 75 [174] "Free block at 431B:0000." 46000 bytes (0xB3B paragraphs) freed. Address of first byte beyond block is 4E56:0000. 76 [174] "Free block at 37DF:0000." 46000 bytes (0xB3B paragraphs) freed. Address of first byte beyond block is 431A:0000. 77 [174] "Free block at 2CA3:0000." 46000 bytes (0xB3B paragraphs) freed. Address of first byte beyond block is 37DE:0000. 78 [174] "Free block at 0:0000." Error: null pointer 79 [200] Message: Memory log compacted. 80 "Ascertain maximum available." 469216 bytes. Number of entries in the memory allocation log: 80 *** Block/array ID = 23 *** 3 [151] "Allocate 40000 bytes." 2500 (0x9C4) paragraphs (40000 bytes) allocated at 2B9E:0000. Address of first byte beyond block is 3562:0000. 25 [174] "Free block at 2B9E:0000." 40000 bytes (0x9C4 paragraphs) freed. Address of first byte beyond block is 3562:0000. *** Block/array ID = 24 *** 4 [151] "Allocate 40000 bytes." 2500 (0x9C4) paragraphs (40000 bytes) allocated at 3563:0000. Address of first byte beyond block is 3F27:0000. 24 [174] "Free block at 3563:0000." 40000 bytes (0x9C4 paragraphs) freed. Address of first byte beyond block is 3F27:0000. ... [Most of this report, report #2, is not reproduced here.] *** Block/array ID = 139 *** 65 [151] "Allocate 46000 bytes." 2875 (0xB3B) paragraphs (46000 bytes) allocated at 8683:0000. Address of first byte beyond block is 91BE:0000. 69 [174] "Free block at 8683:0000." 46000 bytes (0xB3B paragraphs) freed. Address of first byte beyond block is 91BE:0000. *** Block/array ID = 140 *** 66 [151] "Allocate 46000 bytes." 2875 (0xB3B) paragraphs (46000 bytes) allocated at 91BF:0000. Address of first byte beyond block is 9CFA:0000. 68 [174] "Free block at 91BF:0000." 46000 bytes (0xB3B paragraphs) freed. Address of first byte beyond block is 9CFA:0000. Errors not specific to a memory block or array: 14 [151] "Allocate 40000 bytes." Error: insufficient memory Maximum available is 36048 bytes. 26 [174] "Free block at 0:0000." Error: null pointer 27 [151] "Allocate 46000 bytes." Error: insufficient memory Maximum available is 39808 bytes. 28 [174] "Free block at 0:0000." Error: null pointer 43 [151] "Allocate 40000 bytes." Error: insufficient memory Maximum available is 34512 bytes. 55 [174] "Free block at 0:0000." Error: null pointer 67 [151] "Allocate 46000 bytes." Error: insufficient memory Maximum available is 12224 bytes. 78 [174] "Free block at 0:0000." Error: null pointer 32 memory blocks (or arrays) were allocated. 32 memory blocks (or arrays) were freed. 4 memory operations had insufficient memory. 4 null pointers passed. (d) The HEAPFREE.C program /* HEAPFREE.C * last mod.: 15-MAY-91 */ #include #include char msg[70]; struct far_heap_info_t heap_info; /*-----------*/ void main(void) { int err_flag; long heap_used; Ulong max_size = mem_max(&err_flag); if ( err_flag ) printf("\nError: %s\n",mem_err_msg(err_flag,msg)); else Ú{ ³far_heap_info(&heap_info); ³if ( !heap_info.heap_ok ) ³ printf("\nFar heap is not OK.\n"); ³else ³ Ú{ ³ ³printf("\nThe far heap begins at %Fp",heap_info.heap_bottom); ³ ³printf("\ and ends at %Fp.",heap_info.heap_top); ³ ³printf("\nThere are %u blocks in the far heap",heap_info.blocks); ³ ³printf(" and %u of these blocks %s free.", ³ ³ heap_info.free_blocks,(heap_info.free_blocks==1?"is":"are")); ³ ³printf("\nLargest free block = %lu bytes (%luK)", ³ ³ max_size,max_size>>10); ³ ³printf("\nFree space in the far heap = %ld bytes (%ldK)", ³ ³ heap_info.heap_free,heap_info.heap_free>>10); ³ ³printf("\nTotal space in the far heap = %ld bytes (%ldK)", ³ ³ heap_info.heap_size,heap_info.heap_size>>10); ³ ³heap_used = heap_info.heap_size - heap_info.heap_free; ³ ³printf("\nPercentage of far heap in use = %d%%\n", ³ ³ (100*heap_used)/heap_info.heap_size); ³ À} À} } This program is based on the far_heap_info() function. It produces output such as the following: The far heap begins at 09CB:0000 and ends at A000:0000. There are 12 blocks in the far heap and 2 of these blocks are free. Largest free block = 489456 bytes (477K) Free space in the far heap = 489504 bytes (478K) Total space in the far heap = 615072 bytes (600K) Percentage of far heap in use = 20% (e) The HEAPWALK.C program 1: /* HEAPWALK.C 2: * last mod.: 6-OCT-91 3: */ 4: 5: #include 6: #include 7: #include 8: #include 9: 10: char msg[70]; 11: 12: /*-----------*/ 13: void main(void) 14: { 15: Uint block_number = 0; 16: int err_flag; 17: Far_ptr ptr = (Far_ptr)NULL; 18: struct block_info_t block_info; 19: 20: printf("\nblock block address size process ID"); 21: while ( TRUE ) 22: Ú{ 23: ³ptr = next_memory_block(ptr,&block_info,&err_flag); 24: ³if ( err_flag ) 25: ³ Ú{ 26: ³ ³printf("\n%s\n",mem_err_msg(err_flag,msg)); 27: ³ ³exit(1); 28: ³ À} 29: ³if ( ptr == (Far_ptr)NULL ) 30: ³ Ú{ 31: ³ ³printf("\n End of heap\n"); 32: ³ ³exit(0); 33: ³ À} 34: ³printf("\n%4u %Fp ", 35: ³ block_number++,ptr); 36: ³printf("0x%06lX ",block_info.size); 37: ³if ( block_info.process_id > 0x100 ) 38: ³ printf("0x%04X ",block_info.process_id); 39: ³else 40: ³ printf(" "); 41: ³switch ( block_info.type ) 42: ³ Ú{ 43: ³ ³case 0: printf("free "); break; 44: ³ ³case 1: printf("program "); break; 45: ³ ³case 2: printf("environment "); break; 46: ³ ³default: 47: ³ ³ if ( block_info.process_id > 0x100 ) 48: ³ ³ printf("data "); 49: ³ À} 50: ³if ( block_info.name[0] ) 51: ³ printf("%s",block_info.name); 52: À} 53: } 54: This program demonstrates how to walk through the far heap, examining each block on the way. When next_memory_block() is called with a NULL value for the first parameter, it returns a far pointer to the first memory block in the far heap. When this function is again called, with this pointer passed as the value of the first parameter, a pointer to the next memory block (if there is one) is returned, and so on. At each stage next_memory_block() returns the process ID, the size, etc., of the next memory block in the structure at block_info. (The process ID of any memory block is the segment address of the program segment prefix of the process which caused the allocation of this block.) If the program is compiled as HEAPWALK.EXE then the output is typically as follows: block block address size process ID 0 0254:0000 0x001C30 1 0418:0000 0x000040 2 041D:0000 0x000940 0x041D program COMMAND 3 04B2:0000 0x000040 free 4 04B7:0000 0x000200 0x041D environment COMMAND 5 04D8:0000 0x0000C0 0x078F environment CGCLOCK 6 04E5:0000 0x002A90 0x04E5 program IMOUSE 7 078F:0000 0x0002A0 0x078F program CGCLOCK 8 07BA:0000 0x000170 free 9 07D2:0000 0x001020 0x07D2 program DOSKEY 10 08D5:0000 0x000180 0x08EE environment HEAPWALK 11 08EE:0000 0x0141F0 0x08EE program HEAPWALK 12 1D0E:0000 0x082F20 free End of heap The program names, at the ends of the lines, will appear only if the program is running under DOS 4.0 or later. [The other demonstration programs are explained in the manual.] Copyright 1991 Dolphin Software