简体   繁体   中英

Comparing the Performance of Pointers' Allocation in C/C++

What is the best way to compare pointers allocation/de-allocation in C/C++? Please consider the performance as the point of view.

The code includes a comparison of the following dynamic allocation types:

  • Malloc/Free
  • New/Delete
  • std::auto_ptr
  • std::shared_ptr
  • std::unique_ptr
  • std::allocator/deallocator

Let's start with this code snippet:

#include <stdlib.h> // I intended to use C for malloc. Though not cstdlib
#include <sys/time.h>
#include <iostream>
#include <memory>

#define Million 1000000
#define Alls 100 * Million

long calculate_time(struct timeval start, struct timeval end){

    long start_micro = (start.tv_sec * Million) + start.tv_usec;
    long end_micro = (end.tv_sec * Million) + end.tv_usec;
    long elapsed_time = end_micro - start_micro;
    std::cout << "Elapsed time: " << elapsed_time << " usec";
    std::cout << " (" << Alls / elapsed_time << " allocations/microseconds)" << std::endl;
}


/* 
* Version: C
* Allocation: Malloc
* Deallocation: Free
*/
void c_pointer (){


    int counter = 0;
    do{

        int *p = (int *) malloc (sizeof (int));
        *p =5;
        free(p);
        counter ++;
    } while (counter < Alls);
}


/* 
* Version: C++98
* Allocation: New
* Deallocation: Delete
*/
void cpp98_pointer (){

    int counter = 0;
    do{

        int *p = new int (5);
        delete p;
        counter ++;
    } while (counter < Alls);
}


/* 
* Version: C++98 till C++17
* Allocation: std::auto_ptr
* Deallocation: Automatically
*/
void cpp98_auto_ptr (){

    int counter = 0;
    do{
        std::auto_ptr<int> p(new int);
        *p = 5;
        counter ++;
    } while (counter < Alls);
}


/* 
* Version: C++11
* Allocation: std::shared_ptr
* Deallocation: Automatically
*/
void cpp11_shared_ptr (){

    int counter = 0;
    do{
        std::shared_ptr<int> p(new int);
        *p = 5;
        counter ++;
    } while (counter < Alls);
}


/* 
* Version: C++11
* Allocation: std::unique_ptr
* Deallocation: Automatically
*/
void cpp11_unique_ptr (){

    int counter = 0;
    do{
        std::unique_ptr<int> p(new int); 
        *p = 5;
        counter ++;
    } while (counter < Alls);

}


/* 
* Version: C++98
* Allocation: std::allocator
* Deallocation: Deallocate
*/
void cpp98_allocator (){

    int counter = 0;
    do{

        std::allocator<int> a;
        int* p = a.allocate(1);
        a.construct(p, 1);
        *p =5;
        a.deallocate(p, 1);
        counter ++;
    } while (counter < Alls);

}


int main (){

    for (int i= 0 ; i < 6; i++){

        struct timeval t1, t2;
        gettimeofday(&t1, NULL);

        switch(i){
            case 0:
                std::cout << "C - Malloc/Free:" << std::endl;
                c_pointer();
                break;
            case 1:
                std::cout << "C++98 - New/Delete:" << std::endl;
                cpp98_pointer();
                break;
            case 2:
                // From C++98 until C++17 (Removed in C++17)
                std::cout << "C++98 - auto_ptr:" << std::endl;
                cpp98_auto_ptr();
                break;
            case 3:
                // From C++11
                std::cout << "C++11 - shared_ptr:" << std::endl;
                cpp11_shared_ptr();
                break;
            case 4:
                // From C++11
                std::cout << "C++11 - unique_ptr:" << std::endl;
                cpp11_unique_ptr();
                break;
            default:
                // Deprecated in C++98
                std::cout << "C++98 - Default Allocator:" << std::endl;
                cpp98_allocator();
                break;
        }

        gettimeofday(&t2, NULL);
        calculate_time(t1, t2);
    }

    return 0;
}

On my own laptop, results are as follows:

C - Malloc/Free:
Elapsed time: 1519052 usec (65 allocations/microseconds)
C++98 - New/Delete:
Elapsed time: 1718064 usec (58 allocations/microseconds)
C++98 - auto_ptr:
Elapsed time: 2334505 usec (42 allocations/microseconds)
C++11 - shared_ptr:
Elapsed time: 10197285 usec (9 allocations/microseconds)
C++11 - unique_ptr:
Elapsed time: 11785931 usec (8 allocations/microseconds)
C++98 - Default Allocator:
Elapsed time: 3487610 usec (28 allocations/microseconds)

First, when you compile with retail optimizations turned on, you get dramatically different results. (My quick port to Windows and some fixups in your code, including not taking a timing measurement until after the cout statement):

C - Malloc/Free:
Elapsed time: 469 msec     (21321 allocations/second)
C++98 - New/Delete:
Elapsed time: 500 msec     (20000 allocations/second)
C++11 - auto_ptr:
Elapsed time: 484 msec     (20661 allocations/second)
C++11 - shared_ptr:
Elapsed time: 1157 msec     (8643 allocations/second)
C++11 - unique_ptr:
Elapsed time: 484 msec     (20661 allocations/second)

Everything but the shared_ptr has the same speed. shared_ptr has to allocate some locking constructs (mutex) since it has be thread safe with regards to reference countnig and weak_ptr assignments.

Second, your methodology is flawed, each allocation is followed by a deallocation followed by an identically sized allocation. It's possible the compiler can just optimize that all away since the allocation pointer is not used for anything.

And it's also likely that the top level memory manager can give return a pointer fast from the heap since it has just been handed back a pointer of identical size. It never has to go back to the lower heap to increase the heap.

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