views:

96

answers:

6

I have the following problem in a Visual C++ 9 program. There's a huge object that logically contains several subobjects. I can either store the subobjects inside the object or store pointers to subobjects allocated separately.

The key point here is that there's always one instance of suboject of each type in one outer object - it is always of the same size and its lifetime is exactly the same as of the outer object, so the two choices above are logically identical - the program structure and logic don't change.

Here's how my thought develops:

  1. If I store subobjects inside traversing to them will become slightly faster, but that's not what I care about the most - I profiled the program and that's not the bottleneck.
  2. If I store subobjects inside the outer object will occupy more memory, so I'll allocate larger blocks and that might fragment memory more compared to allocating lots of similarly small subobjects separately - freed memory blocks might be less reusable (I'm not sure, I just suppose that).
  3. Of course, less allocations will make the program faster, but that's not very important - again I profiled the program and allocations time is not a bottleneck.
  4. Since each allocation induces a memory overhead with larger objects I will in fact consume less memory and that is good for my program that works with huge amounts of data.

Meanwhile memory fragmentation is what really bothers me - I need my program to be very stable and able to run from months continuously.

How do I make my decision? Are there any methods for deciding whether I should choose smaller object or bigger objects given the considerations above?

+2  A: 

Allocating a few large objects will fragment memory less than allocating a larger number of smaller objects. Even more important, since a larger percentage of your objects are exactly the same size, you'll often be able to reuse a freed block exactly as-is. Splitting your object up into a larger number of smaller objects will generally make fragmentation more of a problem, not less.

If you find that fragmentation does become a problem, you generally want to deal with that by defining your own allocator.

Jerry Coffin
+1  A: 

I would say you would get less memory fragmentation by storing one large object rather than many small ones. Think about it this way. If you have 100 MB of memory and you allocate 1 50MB object then at worst case you will have two 25MB blocks available.

If however you allocate two 25 MB blocks then worst case you might have 3 16MB blocks. That is more fragmentation rather than less.

bradgonesurfing
A: 

It's a far superior option to perform as few separate allocations as possible. This is because the allocation involves overhead which is reduced, both in memory and time, and in addition, the contiguous memory is far faster to access because there's far reduced risk of cache misses, and also reduces fragmentation (although I've never had a problem with fragmentation personally).

The simple fact is that composing with subobjects is the fastest and smallest option in every possible regard. If you can do it, do.

It also has many maintenance-related upsides, such as the automatic constructor/assignment operator generations.

DeadMG
A: 

If you are using smart pointer, you don't need no worry about destroyed your objects, so the code roughly equivalent than using aggregated object (except for the slight overhead in memory and performance). However by experience specification changes with time, (you might will need to swap subobjects between objects later) it's more flexible to use pointer than subobject. And in the worse case (if you have memory or performance) and want to go back subobject, you can easily create a subobject and make the old pointer point to it, so you don't to change any bits of code except the constructor , like that (in pseudo code) (you can even use an #ifdef you can change it whenever you want a do some benchmarks if needed)

class A 
{
#ifdef SUBOBJECT
   B __b; 
#endif
   B *b;
   A()
   {
#ifdef SUBOBJECT
     *b = &__b;
#else
     *b = new B();
#endif     
   };

  void f()
  {
    b->f();
  }
}
mb14
A: 

I wouldn't suggest making this decision based on perceived advantages in regards to fragmentation. Instead make the decision based on your class design.

If the sub-objects don't play any part in the public interface of the containing object you can pimpl them, thus reducing the publicly visible interface of the outer object and likely compile time as well. Then you can privately define the implementation of the sub-objects hidden in an implementation with no public visibility.

Alternately if your design benefits from the convenience of automatic management if directly contained objects use that approach.

After making this decision based on design considerations, if you still have concerns about fragmentation the proper way to solve that problem is to take control of the allocation yourself using a custom allocator rather than relying on any particular behavior of the built in allocator used by new.

Mark B
A: 

As others have mentioned here, your assumption that many small allocations is better for fragmentation than fewer large allocations is not correct.

If fragmentation is a big concern, one of the best tools that you can use is pooled memory. You say in the question that the "subobject is always of the same size." If this is true, there's a big opportunity for you to greatly reduce your number of allocations and heap fragmentation. Just create your own allocator object that hands out blocks of memory of sizeof(SubObject). Your outer object will store a pointer to the subobject, which was allocated with your allocator. When it wants to deallocate, it hands the memory back to the allocator object. The allocator object, instead of calling delete, will save the memory block and hand it out the next time it's asked for an allocation. The allocator object will store a list of such blocks and recycle them. This will reduce the number of heap allocations that you do tremendously.

bshields