This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

std::vector: Memory allocation in copy constructor for empty vector


Hi,

in the default constructor of the std::vector a zero sized vector is
created. If this vector is copied
with the copy constructor a memory block of size zero is allocated,
resulting in a real memory allocation.

This behavior has changed as the std::allocator changed from a separate
implementation to the
__glibcxx_base_allocator somewhere around 2004 (we recently changed from
gcc 3.3.2 to 4.1.0).

Because we use something like:
vector <vector <int> > v;
v.resize (1000000);

That gave use a huge bunch of memory allocations :-(

So here are my questions:
1) Is there an easy standard way to change the default allocator? Not per
instance - this would be
   way to much to change :-(
2) Is there a chance that the copy constructor of the vector (or the
allocator) will be changed to
   the former behavior? (I guess the standard don't say anything about
which of both is correct)

I think just changing the default allocator back to the old behavior would
not do the trick
because maybe there is some code that already depends on the 'new'
behavior.

Googling around I have found nothing about this right now (I wonder if we
are the only one
that are affected by this).
OK, but we only found this because we have a replacement of new and delete
to easily fetch
memory leaks. This was designed for about 200,000 to 500,000 allocations
(which was very
much back in 1998 ;-)  now with around 4,000,000 allocations this leads -
at a specific algorithm -
to a runtime of 190 second instead of 0.9 seconds :-(  After fixing the
memory management to
effectively work with millions of allocations we now have 5 seconds left.
Without our memory
management the runtime increased from 0.7 to 1.0 seconds. Not really
recognizable :)
But it still wastes a few MB of memory...

Below is a little program to check the default constructor and the copy
constructor.
The number of the zero sized news is the one to look at...

Thanks for your time

ciao Harald

-------------------------------
#include <iostream>
#include <vector>

unsigned int new_counter = 0;
unsigned int zero_sized_news = 0;

void *operator new (size_t size) throw (std::bad_alloc)
{
  void *p;

  /* malloc (0) is unpredictable; avoid it.  */
  if (size == 0)
    {
      size = 1;
      ++zero_sized_news;
    }

  ++new_counter;

  p = malloc (size);

  if (p == 0)
    throw std::bad_alloc ();

  return p;
}

void operator delete (void *ptr) throw()
{
  if (ptr != 0)
    free (ptr);
}

int main ()
{
  std::vector<std::vector<int> > * v;

  unsigned int zsn1 = zero_sized_news;
  std::cerr << "zero sized news: " << zero_sized_news << std::endl
          << "overall news:    " << new_counter << std::endl
          << "allocating empty vector:" << std::endl;

  v = new std::vector<std::vector<int> >;

  unsigned int zsn2 = zero_sized_news;
  std::cerr << "zero sized news: " << zero_sized_news << std::endl
          << "overall news:    " << new_counter << std::endl
          << "that are " << zsn2 - zsn1 << " for empty vector" << std::endl
          << "initializing 10 empty vectors with copy constructor:"
          << std::endl;

  v->resize (10);

  unsigned int zsn3 = zero_sized_news;
  std::cerr << "zero sized news: " << zero_sized_news << std::endl
          << "overall news:    " << new_counter << std::endl
          << "that are " << zsn3 - zsn2
          << " for copy constructor of vector" << std::endl;

  return 0;
}
-------------------------------


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]