2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
16 * Files for debugging memory allocator
25 // Warning( "MEM: Too many malloc's!" );
26 // Warning( "MEM: Malloc returnd an already alloced block!" );
27 // Warning( "MEM: Malloc Failed!" );
28 // Warning( "MEM: Freeing the NULL pointer!" );
29 // Warning( "MEM: Freeing a non-malloced pointer!" );
30 // Warning( "MEM: %d/%d check bytes were overwritten at the end of %8x", ec, CHECKSIZE, buffer );
31 // Warning( "MEM: %d blocks were left allocated!", numleft );
48 #include <Processes.h>
49 ubyte virtual_memory_on = 0;
51 #if defined(RELEASE) || defined(NDEBUG)
59 static int sMemStatsFileInitialized = false;
60 static FILE* sMemStatsFile = NULL;
61 static char sMemStatsFileName[32] = "memstats.txt";
62 #endif // end of if MEMSTATS
64 #else // no memstats on pc
68 #define FULL_MEM_CHECKING 1
70 #if defined(FULL_MEM_CHECKING) && !defined(NDEBUG)
73 #define CHECKBYTE 0xFC
75 #define MAX_INDEX 10000
77 static void *MallocBase[MAX_INDEX];
78 static unsigned int MallocSize[MAX_INDEX];
79 static unsigned char Present[MAX_INDEX];
80 static char * Filename[MAX_INDEX];
81 static char * Varname[MAX_INDEX];
82 static int LineNum[MAX_INDEX];
83 static int BytesMalloced = 0;
85 int show_mem_info = 1;
87 static int free_list[MAX_INDEX];
89 static int num_blocks = 0;
91 static int Initialized = 0;
93 static int LargestIndex = 0;
95 int out_of_memory = 0;
97 void mem_display_blocks();
105 for (i=0; i<MAX_INDEX; i++ )
119 atexit(mem_display_blocks);
123 // need to check for virtual memory since we will need to do some
124 // tricks based on whether it is on or not
128 THz theD2PartionPtr = nil;
129 unsigned long thePartitionSize = 0;
132 MoreMasters(); // allocate 240 more master pointers (mainly for snd handles)
136 virtual_memory_on = 0;
137 if(Gestalt(gestaltVMAttr, &mem_type) == noErr)
139 virtual_memory_on = 1;
142 sMemStatsFile = fopen(sMemStatsFileName, "wt");
144 if (sMemStatsFile != NULL)
146 sMemStatsFileInitialized = true;
148 theD2PartionPtr = ApplicationZone();
149 thePartitionSize = ((unsigned long) theD2PartionPtr->bkLim) - ((unsigned long) theD2PartionPtr);
150 fprintf(sMemStatsFile, "\nMemory Stats File Initialized.");
151 fprintf(sMemStatsFile, "\nDescent 2 launched in partition of %u bytes.\n",
154 #endif // end of ifdef MEMSTATS
157 #endif // end of ifdef macintosh
161 void PrintInfo( int id )
163 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] );
167 void * mem_malloc( unsigned int size, char * var, char * filename, int line, int fill_zero )
176 // printf("malloc: %d %s %d\n", size, filename, line);
180 unsigned long theFreeMem = 0;
182 if (sMemStatsFileInitialized)
184 theFreeMem = FreeMem();
186 fprintf(sMemStatsFile,
187 "\n%9u bytes free before attempting: MALLOC %9u bytes.",
192 #endif // end of ifdef memstats
194 if ( num_blocks >= MAX_INDEX ) {
195 fprintf( stderr,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs.\n" );
196 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", var, filename, line );
197 Error( "MEM_OUT_OF_SLOTS" );
200 id = free_list[ num_blocks++ ];
202 if (id > LargestIndex ) LargestIndex = id;
206 fprintf( stderr,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs.\n" );
207 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] );
208 Error( "MEM_OUT_OF_SLOTS" );
212 ptr = malloc( size+CHECKSIZE );
214 ptr = (void *)NewPtrClear( size+CHECKSIZE );
218 for (j=0; j<=LargestIndex; j++ )
220 if (Present[j] && MallocBase[j] == (unsigned int)ptr )
222 fprintf( stderr,"\nMEM_SPACE_USED: Malloc returned a block that is already marked as preset.\n" );
223 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], Line[id] );
224 Warning( "MEM_SPACE_USED" );
233 fprintf( stderr, "\nMEM_OUT_OF_MEMORY: Malloc returned NULL\n" );
234 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] );
235 Error( "MEM_OUT_OF_MEMORY" );
238 MallocBase[id] = ptr;
239 MallocSize[id] = size;
241 Filename[id] = filename;
247 BytesMalloced += size;
249 for (i=0; i<CHECKSIZE; i++ )
250 pc[size+i] = CHECKBYTE;
253 memset( ptr, 0, size );
259 int mem_find_id( void * buffer )
263 for (i=0; i<=LargestIndex; i++ )
265 if (MallocBase[i] == buffer )
272 int mem_check_integrity( int block_number )
277 CheckData = (ubyte *)((char *)MallocBase[block_number] + MallocSize[block_number]);
281 for (i=0; i<CHECKSIZE; i++ )
282 if (CheckData[i] != CHECKBYTE ) {
284 fprintf( stderr, "OA: %p ", &CheckData[i] );
287 if (ErrorCount && (!out_of_memory)) {
288 fprintf( stderr, "\nMEM_OVERWRITE: Memory after the end of allocated block overwritten.\n" );
289 PrintInfo( block_number );
290 fprintf( stderr, "\t%d/%d check bytes were overwritten.\n", ErrorCount, CHECKSIZE );
298 void mem_free( void * buffer )
307 unsigned long theFreeMem = 0;
309 if (sMemStatsFileInitialized)
311 theFreeMem = FreeMem();
313 fprintf(sMemStatsFile,
314 "\n%9u bytes free before attempting: FREE", theFreeMem);
317 #endif // end of ifdef memstats
319 if (buffer==NULL && (!out_of_memory))
321 fprintf( stderr, "\nMEM_FREE_NULL: An attempt was made to free the null pointer.\n" );
322 Warning( "MEM: Freeing the NULL pointer!" );
327 id = mem_find_id( buffer );
329 if (id==-1 && (!out_of_memory))
331 fprintf( stderr, "\nMEM_FREE_NOMALLOC: An attempt was made to free a ptr that wasn't\nallocated with mem.h included.\n" );
332 Warning( "MEM: Freeing a non-malloced pointer!" );
337 mem_check_integrity( id );
339 BytesMalloced -= MallocSize[id];
344 DisposePtr( (Ptr)buffer );
352 free_list[ --num_blocks ] = id;
355 void *mem_realloc(void * buffer, unsigned int size, char * var, char * filename, int line)
366 } else if (buffer == NULL) {
367 newbuffer = mem_malloc(size, var, filename, line, 0);
369 newbuffer = mem_malloc(size, var, filename, line, 0);
370 if (newbuffer != NULL) {
371 id = mem_find_id(buffer);
372 if (MallocSize[id] < size)
373 size = MallocSize[id];
374 memcpy(newbuffer, buffer, size);
381 char *mem_strdup(char *str, char *var, char *filename, int line)
385 newstr = mem_malloc((int)strlen(str) + 1, var, filename, line, 0);
391 void mem_display_blocks()
395 if (Initialized==0) return;
399 if (sMemStatsFileInitialized)
401 unsigned long theFreeMem = 0;
403 theFreeMem = FreeMem();
405 fprintf(sMemStatsFile,
406 "\n%9u bytes free before closing MEMSTATS file.", theFreeMem);
407 fprintf(sMemStatsFile, "\nMemory Stats File Closed.");
408 fclose(sMemStatsFile);
411 #endif // end of ifdef memstats
414 for (i=0; i<=LargestIndex; i++ )
416 if (Present[i]==1 && (!out_of_memory))
420 fprintf( stderr, "\nMEM_LEAKAGE: Memory block has not been freed.\n" );
423 mem_free( (void *)MallocBase[i] );
427 if (numleft && (!out_of_memory))
429 Warning( "MEM: %d blocks were left allocated!\n", numleft );
434 void mem_validate_heap()
438 for (i=0; i<LargestIndex; i++ )
440 mem_check_integrity( i );
448 ef = fopen( "DESCENT.MEM", "wt" );
450 for (i=0; i<LargestIndex; i++ )
451 if (Present[i]==1 ) {
452 size += MallocSize[i];
453 //fprintf( ef, "Var:%s\t File:%s\t Line:%d\t Size:%d Base:%x\n", Varname[i], Filename[i], Line[i], MallocSize[i], MallocBase[i] );
454 fprintf( ef, "%12d bytes in %s declared in %s, line %d\n", MallocSize[i], Varname[i], Filename[i], LineNum[i] );
456 fprintf( ef, "%d bytes (%d Kbytes) allocated.\n", size, size/1024 );
462 static int Initialized = 0;
463 static unsigned int SmallestAddress = 0xFFFFFFF;
464 static unsigned int LargestAddress = 0x0;
465 static unsigned int BytesMalloced = 0;
467 void mem_display_blocks();
470 #define CHECKBYTE 0xFC
472 int show_mem_info = 0;
478 SmallestAddress = 0xFFFFFFF;
479 LargestAddress = 0x0;
481 atexit(mem_display_blocks);
485 // need to check for virtual memory since we will need to do some
486 // tricks based on whether it is on or not
490 THz theD2PartionPtr = nil;
491 unsigned long thePartitionSize = 0;
494 MoreMasters(); // allocate 240 more master pointers (mainly for snd handles)
498 virtual_memory_on = 0;
499 if(Gestalt(gestaltVMAttr, &mem_type) == noErr)
501 virtual_memory_on = 1;
504 sMemStatsFile = fopen(sMemStatsFileName, "wt");
506 if (sMemStatsFile != NULL)
508 sMemStatsFileInitialized = true;
510 theD2PartionPtr = ApplicationZone();
511 thePartitionSize = ((unsigned long) theD2PartionPtr->bkLim) - ((unsigned long) theD2PartionPtr);
512 fprintf(sMemStatsFile, "\nMemory Stats File Initialized.");
513 fprintf(sMemStatsFile, "\nDescent 2 launched in partition of %u bytes.\n",
516 #endif // end of ifdef memstats
519 #endif // end of ifdef macintosh
523 void * mem_malloc( unsigned int size, char * var, char * filename, int line, int fill_zero )
534 unsigned long theFreeMem = 0;
536 if (sMemStatsFileInitialized)
538 theFreeMem = FreeMem();
540 fprintf(sMemStatsFile,
541 "\n%9u bytes free before attempting: MALLOC %9u bytes.",
546 #endif // end of ifdef memstats
549 fprintf( stderr, "\nMEM_MALLOC_ZERO: Attempting to malloc 0 bytes.\n" );
550 fprintf( stderr, "\tVar %s, file %s, line %d.\n", var, filename, line );
551 Error( "MEM_MALLOC_ZERO" );
556 ptr = malloc( size + CHECKSIZE );
558 ptr = (void *)NewPtrClear( size+CHECKSIZE );
562 fprintf( stderr, "\nMEM_OUT_OF_MEMORY: Malloc returned NULL\n" );
563 fprintf( stderr, "\tVar %s, file %s, line %d.\n", var, filename, line );
564 Error( "MEM_OUT_OF_MEMORY" );
568 base = (unsigned int)ptr;
569 if ( base < SmallestAddress ) SmallestAddress = base;
570 if ( (base+size) > LargestAddress ) LargestAddress = base+size;
575 BytesMalloced += *psize;
578 memset( ptr, 0, size );
583 void mem_free( void * buffer )
585 int * psize = (int *)buffer;
593 unsigned long theFreeMem = 0;
595 if (sMemStatsFileInitialized)
597 theFreeMem = FreeMem();
599 fprintf(sMemStatsFile,
600 "\n%9u bytes free before attempting: FREE", theFreeMem);
603 #endif // end of ifdef memstats
606 fprintf( stderr, "\nMEM_FREE_NULL: An attempt was made to free the null pointer.\n" );
607 Warning( "MEM: Freeing the NULL pointer!" );
612 BytesMalloced -= *psize;
617 DisposePtr( (Ptr)buffer );
621 void mem_display_blocks()
623 if (Initialized==0) return;
627 if (sMemStatsFileInitialized)
629 unsigned long theFreeMem = 0;
631 theFreeMem = FreeMem();
633 fprintf(sMemStatsFile,
634 "\n%9u bytes free before closing MEMSTATS file.", theFreeMem);
635 fprintf(sMemStatsFile, "\nMemory Stats File Closed.");
636 fclose(sMemStatsFile);
639 #endif // end of ifdef memstats
641 if (BytesMalloced != 0 ) {
642 fprintf( stderr, "\nMEM_LEAKAGE: %d bytes of memory have not been freed.\n", BytesMalloced );
646 fprintf( stderr, "\n\nMEMORY USAGE:\n" );
647 fprintf( stderr, " %u Kbytes dynamic data\n", (LargestAddress-SmallestAddress+512)/1024 );
648 fprintf( stderr, " %u Kbytes code/static data.\n", (SmallestAddress-(4*1024*1024)+512)/1024 );
649 fprintf( stderr, " ---------------------------\n" );
650 fprintf( stderr, " %u Kbytes required.\n", (LargestAddress-(4*1024*1024)+512)/1024 );
654 void mem_validate_heap()
667 // routine to try and compact and purge the process manager zone to squeeze
668 // some temporary memory out of it for QT purposes.
674 THz appZone, processZone;
677 // compact the system zone to try and squeeze some temporary memory out of it
678 MaxMemSys(&heapSize);
680 // compact the Process Manager zone to get more temporary memory
681 appZone = ApplicationZone();
682 tempHandle = TempNewHandle(10, &err); // temporary allocation may fail
683 if (!err && (tempHandle != NULL) ) {
684 processZone = HandleZone(tempHandle);
685 if ( MemError() || (processZone == NULL) ) {
686 DisposeHandle(tempHandle);
689 SetZone(processZone);
690 MaxMem(&heapSize); // purge and compact the Process Manager Zone.
692 DisposeHandle(tempHandle);