在C / C ++中比较指针分配/取消分配的最佳方法是什么?请考虑性能。

该代码包含以下动态分配类型的比较:


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


让我们从以下代码片段开始:

#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;
}


在我自己的笔记本电脑上,结果如下:

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)

最佳答案

首先,在启用零售优化的情况下进行编译时,您会得到截然不同的结果。 (我对Windows的快速移植以及代码中的一些修正,包括直到cout语句之后才进行计时测量):

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)


除了shared_ptr之外的所有东西都具有相同的速度。 shared_ptr必须分配一些锁定结构(mutex),因为它对于引用countnig和weak_ptr分配而言是线程安全的。

其次,您的方法存在缺陷,每个分配之后都有一个重新分配,再分配一个大小相同的分配。编译器可能会优化它,因为分配指针没有用于任何东西。

顶级内存管理器也有可能从堆中快速返回一个指针,因为它刚被递回了相同大小的指针。它永远不必回到较低的堆来增加堆。

07-24 09:43
查看更多