← Back to team overview

unity-dev team mailing list archive

[Ayatana-dev] C++ memory allocation

 

Following a brief IRC chat and seeing some commits go through that replaced new/memset with calloc, I wanted to write up a quick test.

Obviously from a C++ background I'd prefer not to use calloc/free.

In fact my first reaction is to use std::vector. In order to test timings I make a quick test (the attached memtest.cpp file).

tim@elwood:~/sandbox$ g++ --std=c++0x memtest.cpp -o memtest -lrt
tim@elwood:~/sandbox$ ./memtest
Testing 100000 iterations of 100 chars.
	new then memset 0.00980978s
	calloc then free 0.00437177s
	vector 0.0157277s
Testing 100000 iterations of 1000 chars.
	new then memset 0.00911948s
	calloc then free 0.00863989s
	vector 0.0193271s
Testing 100000 iterations of 10000 chars.
	new then memset 0.0332187s
	calloc then free 0.0322801s
	vector 0.0433207s
Testing 100000 iterations of 100000 chars.
	new then memset 0.63054s
	calloc then free 0.628706s
	vector 0.642924s
Testing 100000 iterations of 1000000 chars.
	new then memset 6.24861s
	calloc then free 6.2351s
	vector 6.24997s
test 20.813s

We can see that calloc is faster only at small sizes. What's more, the overhead of using a std::vector decreases rapidly as the size gets larger. One advantage of using a std::vector is that the memory is released for you, no need to use delete or free.

Tim
#include <iostream>
#include <string>
#include <vector>

#include <time.h>
#include <stdlib.h>
#include <string.h>

class Timer
{
public:
  Timer(std::string const& output)
    : output_(output) 
    {
      ::clock_gettime(CLOCK_MONOTONIC, &tm_);
    }
  ~Timer() {
    timespec tm;
    ::clock_gettime(CLOCK_MONOTONIC, &tm);
    double total_time = (tm.tv_sec - tm_.tv_sec) +
      ((tm.tv_nsec - tm_.tv_nsec) / 1e9);
    std::cerr << output_ << " " <<  total_time << "s\n";
  }
private:
  std::string output_;
  timespec tm_;
};

int main()
{
  Timer t("test");

  const int count = 100000;

  for (auto size : {100, 1000, 10000, 100000, 1000000}) {

    std::cerr << "Testing " << count << " iterations of " << size << " chars.\n";
    {
      Timer t("\tnew then memset");
      for (int i = 0; i < count; ++i) {
        char* c = new char[size];
        memset(c, 0, size);
        delete [] c;
      }
    }
    {
      Timer t("\tcalloc then free");
      for (int i = 0; i < count; ++i) {
        char* c = (char*)calloc(size, sizeof(char));
        free(c);
      }
    }
    {
      Timer t("\tvector");
      for (int i = 0; i < count; ++i) {
        std::vector<char> v(size);
      }
    }
  }
}


Follow ups