Sign in to follow this  
chippolot

Trying to limit allocation in a message system

Recommended Posts

So basically, I'm currently working on a message system for my AI which will handle all state changes in the game. So, for example, if there is a piece of trash on the ground, it will send out a "Clean Me" message ever 5 frames. This message class looks like so:

class CMessage
{
public:
	//Message Header//////////////////////
	char*					m_Name;
	IActor*					m_pSender;
	CMailingList*			m_pMailingList;
	int						m_Radius;
	bool					m_JunkFlag;
	char					m_Priority;
	short int				m_Attributes;
	unsigned int			m_Delay;

	//Message Data///////////////////////
	IState*				m_pState;

	CMessage(const char* name, IActor* sender, CMailingList* pMailList, const int &radius,
			 const bool &label, const char &priority, const short int &attributes, IState* state, 
			 const unsigned int &delay = 0);
	~CMessage();
};

The message header gives special information about the message like who sent it, who it is being sent to, the radius from the sender in which the message is valid, if it is a must read message, and so on. Each message also has a pointer to a state. The point of each message is that if it is "read" by an AI entity, then the state will be pushed onto the entity's state stack. So, the "Clean Me" message would have a pointer to a CleanObj state. The problem I've been trying to tackle is is that these pointers currently point to allocated memory. They can't simply point to a local state, becuase it would lose scope befor all the AI entities check for messages. So, each message has an allocated state. However, most of the messages in the game will never be "read" by the AI simply becuase the AI is too far away or doesn't match the receiver's criteria. Each time a message is not "read", that state which is linked to it must be deleted. Messages will be sent out frequently, so I don't want to have to allocate and free memory several times each frame. However, the state pointers are in the form of abstract base class pointers. I was thinking of having each AI entity simply have a list of 5 or so premade states which they could fill in and then their messages could point to those. However, there are 15 or so state types in the game (which all inherit from IState) and I wouldn't want to have each AI have 5 copies of each kind of state. I think I'm missing important here, but I'm only a sophomore at Digipen and only starting to learn the ins and outs of memory management... can anyone help me with this problem?

Share this post


Link to post
Share on other sites
You could try allocating a fixed amount of them at start up and recycling them. Check out the placement new operator.

However this only works if your messages are all the same structure or class. I don't see why you would have to recreate the same message eac time. Couldn't you just recycle it by refreshing its date stamp and other info??

Cheers
Chris

Share this post


Link to post
Share on other sites
what you need is an allocation pool, a one-time-init bonanza of memory that can be reused and re-"allocated" as needed.

basically, you allocate a large block of memory on startup, then you track how its given out, and when it should be released, in your case its pretty simple because you're only storing one data type so i guess you can allocate say 50 * sizeof(LargestMessage)

here's a quickey run down of a very very simple implementation

#include <iostream>

// simple data structure
struct message_s {
int val_2; // these are bogus, change as need but
int val_1; // watch out for certain things like pointers
int blockIndex;
};

template< int blockCount, int blockSize >
class BlockAllocator
{
std::vector< unsigned char > memoryPool;
std::vector< bool > allocationInfo;

typedef std::vector< bool >::iterator ALLOCATION_FINDER;

public:
virtual ~BlockAllocator() {}

BlockAllocator() {
// allocate enough memory (in bytes)
memoryPool.resize( blockCount * blockSize );
allocationInfo.resize( blockCount ); // init tracking flags
}

int allocateBlock() {
ALLOCATION_FINDER i = allocationInfo.begin();
int index = 0;
for(; i != allocationInfo.end(); i++, index++ ) {
if( (*i) == false )
break;
}

if( i != allocationInfo.end() ) {
allocationInfo[index] = true;
return index;
}

//failed
return -1;
}

unsigned char* getBlock( int blockIndex ) {
if( blockIndex > -1 && blockIndex < (int)allocationInfo.size() ) {
// zero the memory
memset( &memoryPool[ blockIndex * blockSize ], 0, blockSize );

// return the address
return &memoryPool[ blockIndex * blockSize ];
}
return NULL; //failed
}

void freeBlock( int blockIndex ) {
if( blockIndex > -1 && blockIndex < (int)allocationInfo.size() )
allocationInfo[blockIndex] = false;
}
};

// some helper defines
const int MAX_BLOCK_NEEDED = 5;
typedef BlockAllocator< MAX_BLOCK_NEEDED, sizeof(message_s) > BlockAllocator_t;

// helper function
message_s *makeMessage( BlockAllocator_t& alloc, int val1, int val2 )
{
int block = alloc.allocateBlock();
if( block == -1 ) return NULL;
// unfortunatly have to use C-style cast here (?)
message_s *ptr = (message_s*) ( alloc.getBlock( block ) );
ptr->blockIndex = block;
ptr->val_1 = val1;
ptr->val_2 = val2;
return ptr;
};

// helper funciton
void displayMessage( message_s* m ) {
if( m != NULL )
std::cout << "Block: " << m->blockIndex << ", values: "
<< m->val_1 << ", " << m->val_2 << std::endl;
}

int main()
{
BlockAllocator_t alloc;

message_s *m1 = makeMessage( alloc, 20, 40 );
message_s *m2 = makeMessage( alloc, 50, 50 );
message_s *m3 = makeMessage( alloc, 10, 10 );

displayMessage( m1 );
displayMessage( m2 );
displayMessage( m3 );

// test out the "deallocator"
alloc.freeBlock( m1->blockIndex );
m1 = makeMessage( alloc, 4000, 4000 );

displayMessage( m1 );
displayMessage( m2 );
displayMessage( m3 );

return 0;
}





that should all compile, and give you some ideas. one thing that im not sure about is how safe the method would be, you need to be very carefull about how you handle your pointers etc.

Cheers
-danu

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this