Reuse memory
From Sidvind
Contents |
[edit] Description
It is commonly known that malloc/free and new/delete is expensive. In real-time applications we might have to create and destroy a lot of objects so this can become quite costly. What if we could reuse the object instead of deleting and later creating another? The idea is basically a static member function that creates or reuses the object and a method that discards it. This applies to c++ classes but the idea could be transformed to anything that allocates/deallocates memory. After reading this article you should hopefully be able to adopt this to your own code.
[edit] Object creation
| Code: Class prototype |
class Object {
public:
Object(int a);
static Object* Object::construct(int a)
void discard();
void setA(int a);
private:
int _a;
int _retainCount;
static std::vector<Object*> _pool;
};
|
| Code: The magic |
Object* Object::construct(int a){
if ( _pool.empty() ){
return new Object(a);
}
Object* obj = _pool.back();
_pool.pop_back();
obj->setA(a);
return obj;
}
|
When we need an object we call Object::construct(...) instead of new Object(...). If no objects exists in the pool a new object is created using regular new. However, if an object exists one is popped from the pool and is reconstructed.
[edit] Discard the object
| Code: Basic discarding |
void Object::discard(){
_pool.push_back(this);
}
|
This does work but there is a lot of problems with this. The way I see it the largest problem is the pointer is still valid. It would also be a problem if the pointer would be stored in several places. This is a better version:
| Code: A better way |
void Object::discard(){
_retainCount--;
if ( _retainCount == 0 ){
_pool.push_back(this);
}
}
void discard(Object*& ptr){
ptr->discard();
ptr = 0;
}
|
To discard the object (the pointer at least) call discard(thePointer);. This way the pointer to the object can safely be passed along and copied as much as needed. As long as we increases the retaincount and makes sure we discards the pointer at some point of course. Also note that the last function is a function, not a method or member function. If you don't understand how this works read about retaincounting.
[edit] Performance
The following test created and destroyed 10000 objects 100 times using both methods. It alternated between the two methods. The test was performed on a AMD Athlon XP 2000+ running Gentoo linux.
| Compiler optimization | New/Delete | Reuse |
|---|---|---|
| None | 1.678ms | 2.256ms |
| -O1 | 1.436ms | 0.150ms |
| -O2 | 1.431ms | 0.137ms |
| -O3 | 1.439ms | 0.086ms |
As we can see it was actually slower without the compiler optimization but a LOT faster with it.


