实际上new和delete内部使用的就是free和malloc,而在C中free的参数是void*,malloc返回的是void*。而C++添加了额外的行为就是,malloc之后自动调用够着函数,free之前调用析构函数。所以上面A没有成员数据,而B有,在delete时没有出现错误,原因就在于,在delete pb时,调用B的析构函数,这里没有问题,然后将pb交给free。这就回到了原始的C中,所以整个过程就没有问题。
缺省的Free Store分配器
在C++的缺省内存分配器的性能不好,一个原因是他仅仅是对Cheap分配器的浅层包装(对malloc,realloc,free的包装)。
针对于内置类型(没有构造函数的消耗),实际上C++的new和使用C中的malloc是没有差别的。(C++的new内部仍然使用malloc)。
缺省内存分配器的性能不好,问题出在:
free的参数是void*,malloc返回的是void*,那么编译器在释放内存的时候必然要知道这个内存块得大小,然后再做实际的内存管理操作。那么他就会对分配的内存块登记一些信息,因此登记信息的内存消耗是要考虑的。特别是在分配小型对象的时候。
下面是一个测试:使用mingw32-make, g++编译器
clock_t tm = clock();
char *arr[1024*100];
//6: FixedAllocator fa(1);
//3: arr[0] = (char*)malloc(sizeof(char)*1024*100);
//4: arr[0] = new char[1024*100];
for(int i=0; i<1024*100; ++i)
{
//1: arr[i] = new char;
//2: arr[i] = (char*)malloc(sizeof(char));
//5: arr[i] = func(sizeof(char));//char* func(int){}
//6: arr[i] = (char*)fa.Allocate();
}
cout<<"cost "<<(clock()-tm)*0.001f<<endl;
1:使用new的结果:
time mem
0.022s 2300K
0.02s 2300k
2: 使用malloc的结果
0.03s 2300k
0.007s 2300k
0.01s 2300k
3:一次使用malloc的结果
0s 612k
0s 612k
4:一次使用new的结果
0s 612k
5:在for中调用一个以int为参数的函数
0s 600k
0s 600k
6: 使用Loki中的FixedAllocator,即使用小型分配管理
0.015s 812k
0.015s 812k
从上面的数据可以看出,使用new和malloc针对于内置类型是一致的。而如果我们一次分配这么多的内存和分次分配这么多的内存,的差距是很明显的,可以推出:针对于小型对象使用内置的内存分配在内存上面有额外的开销,可以计算出来大概有16bytes左右。在时间上的开销也是很明显的。
使用小型对象的管理,能够解决对小型对象在内存上的额外消耗。在时间上有一定的改善。
PS: Loki是C++设计新思维书中实现的一个库,针对小型对象的分配使用SmallObj.h,这种实现方法在STL3.2.3中的stl_alloc.h的内存管理也有类似的实现