January 26, 2023, 10:46:47 PM

News:

Own IWBasic 2.x ? -----> Get your free upgrade to 3.x now.........


Counting unfreed memory

Started by Parker, March 15, 2007, 11:21:10 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Parker

March 15, 2007, 11:21:10 PM Last Edit: March 16, 2007, 11:12:02 PM by Parker
This came up in the EBASIC OOP tutorials, so I decided to expand on it a little. This is Aurora code but the same concepts apply to EBASIC. This code redefines the __NEW and __DELETE functions which are called by the compiler when you use new and delete and replaces them with _mynew and _mydelete. This is done using the NASM preprocessor. From there, I handle memory allocation and deallocation, as well as adding a reference to a list of global memory.

Don't use any of the subroutines that are all in lower case. Those are for internal use by the utility. The exception is free_global_list(), which should be called automatically but I couldn't find an ONEXIT and atexit from C's library doesn't seem to work.

Call DumpUnfreedMemory() to list the unfreed memory to the console, and use FreeLostMemory to free that memory. The main method demonstrates it.

declare import,GlobalAlloc(flags as unsigned int,size as int),unsigned int;
declare import,GlobalFree(p as unsigned int),unsigned int;

#define _ALLOC_TAG 0x19F30AD7

CPointerList *alloclist = 0;
int _dont_store_memory = 0;

struct _alloc_info
{
unsigned int tag;
void *address;
unsigned int size;
void *listnode;
}

// The following methods aren't meant for general use.

#asm
%define __NEW _mynew
%define __DELETE _mydelete
#endasm

global sub get_type_size( int type ),int
{
switch( type )
{
case TYPE_STRING:
return 255;
case TYPE_WSTRING:
return 512;
case TYPE_BYTE:
case& TYPE_USER:
return 1;
case TYPE_WORD:
return 2;
case TYPE_DOUBLE:
case& TYPE_INT64:
return 8;
default:
return 4;
}
}

global sub add_global_pointer( _alloc_info *info )
{
if( alloclist == 0 )
{
_dont_store_memory = 1;
alloclist = new(CPointerList, 1);
_dont_store_memory = 0;
alloclist->Create( );
}

alloclist->AddHead( info );
info->listnode = alloclist->GetFirst( );
}

global sub remove_global_pointer( void *node )
{
if( alloclist == 0 )
return;

alloclist->Remove( node );
}

global sub _mynew( int type, int size ),unsigned int
{
_alloc_info *info;

size *= get_type_size( type & 0xFF );
if( _dont_store_memory == 0 )
size += sizeof( _alloc_info );

info = GlobalAlloc( 0x40, size );
if( _dont_store_memory != 0 )
return info;

info->tag = _ALLOC_TAG;

info->size = size - sizeof( _alloc_info );
info->address = info + sizeof( _alloc_info );

add_global_pointer( info );

return info->address;
}

global sub _mydelete( pointer p )
{
if( p < sizeof( _alloc_info ) )
return;

p -= sizeof( _alloc_info );

if( *(_alloc_info)p.tag != _ALLOC_TAG )
{
print( "Delete error - invalid pointer" );
return;
}

remove_global_pointer( *(_alloc_info)p.listnode );
GlobalFree( p );
}

// Feel free to use these methods.
global sub FreeLostMemory( )
{
_alloc_info *info = 0;
void *n, *temp;

if( alloclist == 0 )
return;

n = alloclist->GetFirst( );
while( n != 0 )
{
info = alloclist->GetData( n );
GlobalFree( info );
temp = n;
n = alloclist->GetNext( n );
alloclist->Remove( temp );
}
}

global sub DumpUnfreedMemory( )
{
_alloc_info *info = 0;
int count = 0;

if( alloclist == 0 )
{
print( "No memory recorded." );
return;
}

print( "\n--- Listing undeleted memory ---\n" );
for( void *n = alloclist->GetFirst( ); n; n = alloclist->GetNext( n ) )
{
info = alloclist->GetData( n );
print( "Address: 0x", NumToHex( info->address ), "; Size (bytes): ", info->size );
count++;
}
print( "--- Found ", count, " unfreed memory addresses ---" );
}

global sub free_global_list( )
{
if( alloclist != 0 )
{
GlobalFree( alloclist );
alloclist = 0;
}
}

// Test

struct Type12Bytes
{
int x, y, z;
}

global sub main( )
{
int *x;
byte *y;
Type12Bytes *t12;

x = new( int, 1 );
y = new( byte, 1 );
t12 = new( Type12Bytes, 1 );

DumpUnfreedMemory( );

delete x;
delete t12;

DumpUnfreedMemory( );

FreeLostMemory( );

DumpUnfreedMemory( );

print( "Done." );
free_global_list( );
do{}until(getkey()!="");
}


Edit - updated free_global_list(), removed unneeded count variable from FreeLostMemory().

Haim

Thanks for sharing this.
It is something I was missing badly.

Haim