It sounds like fragmentation. Fragmentation is caused by the fact that you select objects on the stack, for example:
object1
object2
object3
object4
And then deleting some objects
object1
object3
object4
You now have a hole in your unused memory. If you select another object that is too large for the hole, the hole will be wasted. After all, with enough memory junk, you might end up with so many holes that they lose memory.
A way to solve this problem is to select the correct memory requirements. If you have certain objects that, as you know, you create many of them, try and make sure that they are the same size.
You can use the pool to make the allocation more efficient for a particular class ... or at least let you track it better so that you can understand what is happening and come up with a good solution.
One way to do this is to create one static:
struct Slot { Slot() : free(true) {} bool free; BYTE data[20];
Create a pool before starting the program and pre-allocate it so that it is as maximum as the maximum requirements for your program. You might want HeapAlloc (or the equivalent on your OS so that you can control when it appears from somewhere in your application).
Then redefine the new and delete operators for the suspicious class so that they return slots from this vector. So, your objects will be saved in this vector.
You can override new ones and delete for classes of the same size that will be placed in this vector.
Create pools of different sizes for different objects.
Just go for the worst offenders first.
I already did something similar before, and this solved my problem on the embedded device. I also used a lot of STLs, so I created a custom distributor (google for stl custom allocator - there are many links). This was useful for records stored in the mini-database used by my program.