在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分配而言是线程安全的。其次,您的方法存在缺陷,每个分配之后都有一个重新分配,再分配一个大小相同的分配。编译器可能会优化它,因为分配指针没有用于任何东西。
顶级内存管理器也有可能从堆中快速返回一个指针,因为它刚被递回了相同大小的指针。它永远不必回到较低的堆来增加堆。