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 static char rcsid[] = "$Id: mem.c,v 1.4 2001-08-02 22:02:37 thimo Exp $";
20 // Warning( "MEM: Too many malloc's!" );
21 // Warning( "MEM: Malloc returnd an already alloced block!" );
22 // Warning( "MEM: Malloc Failed!" );
23 // Warning( "MEM: Freeing the NULL pointer!" );
24 // Warning( "MEM: Freeing a non-malloced pointer!" );
25 // Warning( "MEM: %d/%d check bytes were overwritten at the end of %8x", ec, CHECKSIZE, buffer );
26 // Warning( "MEM: %d blocks were left allocated!", numleft );
42 #include <Processes.h>
43 ubyte virtual_memory_on = 0;
45 #if defined(RELEASE) || defined(NDEBUG)
53 static int sMemStatsFileInitialized = false;
54 static FILE* sMemStatsFile = NULL;
55 static char sMemStatsFileName[32] = "memstats.txt";
56 #endif // end of if MEMSTATS
58 #else // no memstats on pc
62 #define FULL_MEM_CHECKING 1
64 #if defined(FULL_MEM_CHECKING) && !defined(NDEBUG)
67 #define CHECKBYTE 0xFC
69 #define MAX_INDEX 10000
71 static void *MallocBase[MAX_INDEX];
72 static unsigned int MallocSize[MAX_INDEX];
73 static unsigned char Present[MAX_INDEX];
74 static char * Filename[MAX_INDEX];
75 static char * Varname[MAX_INDEX];
76 static int LineNum[MAX_INDEX];
77 static int BytesMalloced = 0;
79 int show_mem_info = 1;
81 static int free_list[MAX_INDEX];
83 static int num_blocks = 0;
85 static int Initialized = 0;
87 static int LargestIndex = 0;
89 int out_of_memory = 0;
91 void mem_display_blocks();
99 for (i=0; i<MAX_INDEX; i++ )
113 atexit(mem_display_blocks);
117 // need to check for virtual memory since we will need to do some
118 // tricks based on whether it is on or not
122 THz theD2PartionPtr = nil;
123 unsigned long thePartitionSize = 0;
126 MoreMasters(); // allocate 240 more master pointers (mainly for snd handles)
130 virtual_memory_on = 0;
131 if(Gestalt(gestaltVMAttr, &mem_type) == noErr)
133 virtual_memory_on = 1;
136 sMemStatsFile = fopen(sMemStatsFileName, "wt");
138 if (sMemStatsFile != NULL)
140 sMemStatsFileInitialized = true;
142 theD2PartionPtr = ApplicationZone();
143 thePartitionSize = ((unsigned long) theD2PartionPtr->bkLim) - ((unsigned long) theD2PartionPtr);
144 fprintf(sMemStatsFile, "\nMemory Stats File Initialized.");
145 fprintf(sMemStatsFile, "\nDescent 2 launched in partition of %u bytes.\n",
148 #endif // end of ifdef MEMSTATS
151 #endif // end of ifdef macintosh
155 void PrintInfo( int id )
157 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] );
161 void * mem_malloc( unsigned int size, char * var, char * filename, int line, int fill_zero )
171 // printf("malloc: %d %s %d\n", size, filename, line);
175 unsigned long theFreeMem = 0;
177 if (sMemStatsFileInitialized)
179 theFreeMem = FreeMem();
181 fprintf(sMemStatsFile,
182 "\n%9u bytes free before attempting: MALLOC %9u bytes.",
187 #endif // end of ifdef memstats
189 if ( num_blocks >= MAX_INDEX ) {
190 fprintf( stderr,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs.\n" );
191 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", var, filename, line );
192 Error( "MEM_OUT_OF_SLOTS" );
195 id = free_list[ num_blocks++ ];
197 if (id > LargestIndex ) LargestIndex = id;
201 fprintf( stderr,"\nMEM_OUT_OF_SLOTS: Not enough space in mem.c to hold all the mallocs.\n" );
202 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] );
203 Error( "MEM_OUT_OF_SLOTS" );
207 ptr = malloc( size+CHECKSIZE );
209 ptr = (void *)NewPtrClear( size+CHECKSIZE );
213 for (j=0; j<=LargestIndex; j++ )
215 if (Present[j] && MallocBase[j] == (unsigned int)ptr )
217 fprintf( stderr,"\nMEM_SPACE_USED: Malloc returned a block that is already marked as preset.\n" );
218 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], Line[id] );
219 Warning( "MEM_SPACE_USED" );
228 fprintf( stderr, "\nMEM_OUT_OF_MEMORY: Malloc returned NULL\n" );
229 fprintf( stderr, "\tBlock '%s' created in %s, line %d.\n", Varname[id], Filename[id], LineNum[id] );
230 Error( "MEM_OUT_OF_MEMORY" );
235 MallocBase[id] = (void *)ptr;
236 MallocSize[id] = size;
238 Filename[id] = filename;
244 BytesMalloced += size;
246 for (i=0; i<CHECKSIZE; i++ )
247 pc[size+i] = CHECKBYTE;
250 memset( ptr, 0, size );
256 int mem_find_id( void * buffer )
260 for (i=0; i<=LargestIndex; i++ )
262 if (MallocBase[i] == buffer )
269 int mem_check_integrity( int block_number )
274 CheckData = (char *)(MallocBase[block_number] + MallocSize[block_number]);
278 for (i=0; i<CHECKSIZE; i++ )
279 if (CheckData[i] != CHECKBYTE ) {
281 fprintf( stderr, "OA: %p ", &CheckData[i] );
284 if (ErrorCount && (!out_of_memory)) {
285 fprintf( stderr, "\nMEM_OVERWRITE: Memory after the end of allocated block overwritten.\n" );
286 PrintInfo( block_number );
287 fprintf( stderr, "\t%d/%d check bytes were overwritten.\n", ErrorCount, CHECKSIZE );
295 void mem_free( void * buffer )
304 unsigned long theFreeMem = 0;
306 if (sMemStatsFileInitialized)
308 theFreeMem = FreeMem();
310 fprintf(sMemStatsFile,
311 "\n%9u bytes free before attempting: FREE", theFreeMem);
314 #endif // end of ifdef memstats
316 if (buffer==NULL && (!out_of_memory))
318 fprintf( stderr, "\nMEM_FREE_NULL: An attempt was made to free the null pointer.\n" );
319 Warning( "MEM: Freeing the NULL pointer!" );
324 id = mem_find_id( buffer );
326 if (id==-1 && (!out_of_memory))
328 fprintf( stderr, "\nMEM_FREE_NOMALLOC: An attempt was made to free a ptr that wasn't\nallocated with mem.h included.\n" );
329 Warning( "MEM: Freeing a non-malloced pointer!" );
334 mem_check_integrity( id );
336 BytesMalloced -= MallocSize[id];
341 DisposePtr( (Ptr)buffer );
349 free_list[ --num_blocks ] = id;
352 void mem_display_blocks()
356 if (Initialized==0) return;
360 if (sMemStatsFileInitialized)
362 unsigned long theFreeMem = 0;
364 theFreeMem = FreeMem();
366 fprintf(sMemStatsFile,
367 "\n%9u bytes free before closing MEMSTATS file.", theFreeMem);
368 fprintf(sMemStatsFile, "\nMemory Stats File Closed.");
369 fclose(sMemStatsFile);
372 #endif // end of ifdef memstats
375 for (i=0; i<=LargestIndex; i++ )
377 if (Present[i]==1 && (!out_of_memory))
381 fprintf( stderr, "\nMEM_LEAKAGE: Memory block has not been freed.\n" );
384 mem_free( (void *)MallocBase[i] );
388 if (numleft && (!out_of_memory))
390 Warning( "MEM: %d blocks were left allocated!", numleft );
395 void mem_validate_heap()
399 for (i=0; i<LargestIndex; i++ )
401 mem_check_integrity( i );
409 ef = fopen( "DESCENT.MEM", "wt" );
411 for (i=0; i<LargestIndex; i++ )
412 if (Present[i]==1 ) {
413 size += MallocSize[i];
414 //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] );
415 fprintf( ef, "%12d bytes in %s declared in %s, line %d\n", MallocSize[i], Varname[i], Filename[i], LineNum[i] );
417 fprintf( ef, "%d bytes (%d Kbytes) allocated.\n", size, size/1024 );
423 static int Initialized = 0;
424 static unsigned int SmallestAddress = 0xFFFFFFF;
425 static unsigned int LargestAddress = 0x0;
426 static unsigned int BytesMalloced = 0;
428 void mem_display_blocks();
431 #define CHECKBYTE 0xFC
433 int show_mem_info = 0;
439 SmallestAddress = 0xFFFFFFF;
440 LargestAddress = 0x0;
442 atexit(mem_display_blocks);
446 // need to check for virtual memory since we will need to do some
447 // tricks based on whether it is on or not
451 THz theD2PartionPtr = nil;
452 unsigned long thePartitionSize = 0;
455 MoreMasters(); // allocate 240 more master pointers (mainly for snd handles)
459 virtual_memory_on = 0;
460 if(Gestalt(gestaltVMAttr, &mem_type) == noErr)
462 virtual_memory_on = 1;
465 sMemStatsFile = fopen(sMemStatsFileName, "wt");
467 if (sMemStatsFile != NULL)
469 sMemStatsFileInitialized = true;
471 theD2PartionPtr = ApplicationZone();
472 thePartitionSize = ((unsigned long) theD2PartionPtr->bkLim) - ((unsigned long) theD2PartionPtr);
473 fprintf(sMemStatsFile, "\nMemory Stats File Initialized.");
474 fprintf(sMemStatsFile, "\nDescent 2 launched in partition of %u bytes.\n",
477 #endif // end of ifdef memstats
480 #endif // end of ifdef macintosh
484 void * mem_malloc( unsigned int size, char * var, char * filename, int line, int fill_zero )
495 unsigned long theFreeMem = 0;
497 if (sMemStatsFileInitialized)
499 theFreeMem = FreeMem();
501 fprintf(sMemStatsFile,
502 "\n%9u bytes free before attempting: MALLOC %9u bytes.",
507 #endif // end of ifdef memstats
510 fprintf( stderr, "\nMEM_MALLOC_ZERO: Attempting to malloc 0 bytes.\n" );
511 fprintf( stderr, "\tVar %s, file %s, line %d.\n", var, filename, line );
512 Error( "MEM_MALLOC_ZERO" );
517 ptr = malloc( size + CHECKSIZE );
519 ptr = (void *)NewPtrClear( size+CHECKSIZE );
523 fprintf( stderr, "\nMEM_OUT_OF_MEMORY: Malloc returned NULL\n" );
524 fprintf( stderr, "\tVar %s, file %s, line %d.\n", var, filename, line );
525 Error( "MEM_OUT_OF_MEMORY" );
529 base = (unsigned int)ptr;
530 if ( base < SmallestAddress ) SmallestAddress = base;
531 if ( (base+size) > LargestAddress ) LargestAddress = base+size;
536 BytesMalloced += *psize;
539 memset( ptr, 0, size );
544 void mem_free( void * buffer )
546 int * psize = (int *)buffer;
554 unsigned long theFreeMem = 0;
556 if (sMemStatsFileInitialized)
558 theFreeMem = FreeMem();
560 fprintf(sMemStatsFile,
561 "\n%9u bytes free before attempting: FREE", theFreeMem);
564 #endif // end of ifdef memstats
567 fprintf( stderr, "\nMEM_FREE_NULL: An attempt was made to free the null pointer.\n" );
568 Warning( "MEM: Freeing the NULL pointer!" );
573 BytesMalloced -= *psize;
578 DisposePtr( (Ptr)buffer );
582 void mem_display_blocks()
584 if (Initialized==0) return;
588 if (sMemStatsFileInitialized)
590 unsigned long theFreeMem = 0;
592 theFreeMem = FreeMem();
594 fprintf(sMemStatsFile,
595 "\n%9u bytes free before closing MEMSTATS file.", theFreeMem);
596 fprintf(sMemStatsFile, "\nMemory Stats File Closed.");
597 fclose(sMemStatsFile);
600 #endif // end of ifdef memstats
602 if (BytesMalloced != 0 ) {
603 fprintf( stderr, "\nMEM_LEAKAGE: %d bytes of memory have not been freed.\n", BytesMalloced );
607 fprintf( stderr, "\n\nMEMORY USAGE:\n" );
608 fprintf( stderr, " %u Kbytes dynamic data\n", (LargestAddress-SmallestAddress+512)/1024 );
609 fprintf( stderr, " %u Kbytes code/static data.\n", (SmallestAddress-(4*1024*1024)+512)/1024 );
610 fprintf( stderr, " ---------------------------\n" );
611 fprintf( stderr, " %u Kbytes required.\n", (LargestAddress-(4*1024*1024)+512)/1024 );
615 void mem_validate_heap()
628 // routine to try and compact and purge the process manager zone to squeeze
629 // some temporary memory out of it for QT purposes.
635 THz appZone, processZone;
638 // compact the system zone to try and squeeze some temporary memory out of it
639 MaxMemSys(&heapSize);
641 // compact the Process Manager zone to get more temporary memory
642 appZone = ApplicationZone();
643 tempHandle = TempNewHandle(10, &err); // temporary allocation may fail
644 if (!err && (tempHandle != NULL) ) {
645 processZone = HandleZone(tempHandle);
646 if ( MemError() || (processZone == NULL) ) {
647 DisposeHandle(tempHandle);
650 SetZone(processZone);
651 MaxMem(&heapSize); // purge and compact the Process Manager Zone.
653 DisposeHandle(tempHandle);