简体   繁体   中英

Why might std::vector be faster than a raw dynamically allocated array?

The result of a discussion with a colleague I ended up writing benchmarks to test std::vector vs raw dynamically allocated arrays, and ended up with a surprise.

My tests are as follows:

#include "testconsts.h" // defines NUM_INTS across all tests
#include <vector>

int main()
{
    const int numInts = NUM_INTS;
    std::vector<int>                     intVector( numInts );
    int * const                          intArray       = new int[ numInts ];

    ++intVector[0]; // force access to affect optimization
    ++intArray[0];  // force access to affect optimization

    for( int i = 0; i < numInts; ++i )
    {
        ++intArray[i];
    }

    delete[] intArray;
    return 0;
}

and:

#include "testconsts.h" // defines NUM_INTS across all tests
#include <vector>

int main()
{
    const int numInts = NUM_INTS;
    std::vector<int>                     intVector( numInts );
    int *                                intArray       = new int[ numInts ];

    ++intArray[0];  // force access to affect optimization
    ++intVector[0]; // force access to affect optimization

    for( int i = 0; i < numInts; ++i )
    {
        ++intVector[i];
    }

    delete[] intArray;
    return 0;
}

They are compiled with g++ -O3 with gcc 4.4.3

The results of multiple runs of benchmarking using time are similar to:

Array:

real    0m0.757s
user    0m0.176s
sys     0m0.588s

Vector:

real    0m0.572s
user    0m0.268s
sys     0m0.304s

Three things are clear:

  1. Array is faster in user time
  2. Vector is faster less system time
  3. Over all vector won this fight

The question is "why?".

The system time issue I'm guessing must have to do with page faults, but I can't describe for myself exactly why one would have significantly more page faults.

As for the user time issue, it's less interesting to me, but I'm still curious of opinions on that as well. I had imagined it had something to do with initialization, though I'm not passing an initialization value to the vector constructor so I don't know.

The difference is not in the performance of the vector compared to the dynamic array, but in the number of accesses to memory that you perform.

Effectively, in the vector test you are re-accessing cached memory, while in the array version you don't. You pay the price of caching the vector version in either case.

In the vector test, you allocate the dynamic memory for the array but leave it untouched, with the memory never being touched there are no page faults due to that operation. The vector is created, initialized and then the second pass will be accessing already cached data (if the size fits the cache, if it does not, it will not be in cache, but the same cost will be incurred in both versions).

On the other hand when testing the array, the vector constructor initializes the elements, and that means that in the case were you are trying to profile the behavior of the array, the vector contents are walked over and the array elements are walked over. Double the number of memory accesses, page faults and memory used by the application.

You can try modifying the code so that the dynamic allocation is performed like this:

int * intArray = new int[ numInts ](); // note extra ()

Which will value-initialize the whole array, or you initialize the array contents else how. The results of running that modified version of the test should be similar.

Have you run the test more than once? Benchmarking is a hard process, and has to rely on averages to get any kind of meaningful result; it's possible that at the time you were running your array benchmark a few CPU cycles were dedicated to something else, slowing it down. I would expect that given enough results they would be similar, as std::vector is written with a C-style array at it's core.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM