Trying to limit allocation in a message system

Started by
1 comment, last by silvermace 19 years, 5 months ago
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?
Advertisement
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
CheersChris
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 structurestruct 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 definesconst int MAX_BLOCK_NEEDED = 5;typedef BlockAllocator< MAX_BLOCK_NEEDED, sizeof(message_s) > BlockAllocator_t;// helper functionmessage_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 funcitonvoid 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
"I am a donut! Ask not how many tris/batch, but rather how many batches/frame!" -- Matthias Wloka & Richard Huddy, (GDC, DirectX 9 Performance)

http://www.silvermace.com/ -- My personal website

This topic is closed to new replies.

Advertisement