我重载了new和delete来实现我自己的小对象/线程安全分配器。
问题是,当我重载new时,我无法在不破坏通用因果关系或至少破坏编译器的情况下使用new。在我发现的大多数new过载的例子中,都使用Malloc()来进行实际的分配。但是根据我对C++的理解,Malloc()根本没有用例。
多个答案与此类似,其中一些在SO之外的侵权行为较少:In what cases do I use malloc vs new?
我的问题是,在不使用Malloc()的情况下重载操作符new时,如何分配实际内存?
(这是出于好奇心,尽量不要把重载背后的原因看得太重;我对此有一个单独的问题。)
发布于 2011-09-18 11:58:24
简而言之:如果您不想要现有的malloc,则需要实现您自己的堆管理器。
堆管理器是用户级算法,例如Linux中的malloc,Windows中的HeapAlloc。首先,请记住,堆是为分配像4~512字节这样的小尺寸对象而优化的。
如何实现自己的堆管理器?至少,您必须调用一个在您的进程中分配内存块的系统API。有用于Windows的VirtualAlloc和用于Linux的sbrk。这些API分配了很大的内存块,但大小必须是页面大小的倍数。通常情况下,x86和Windows/Linux的页面大小是4KB。
在获得一块页面后,您需要实现自己的算法,如何将这些大内存切分为较小的请求。一个经典的(仍然非常实用的)实现和算法是dlmalloc:http://g.oswego.edu/dl/html/malloc.html
要实现,您需要有几个用于记账的数据结构和一些用于优化的策略。例如,对于16、20、36、256字节这样的小对象,堆管理器维护每个大小的块的列表。因此,这里有一个列表列表。如果请求的大小大于页面大小,则只需调用VirtualAlloc或sbrk。然而,高效的实现是非常具有挑战性的。您不仅必须考虑速度和空间开销,还必须考虑缓存局部性和碎片。
如果您对针对多线程环境优化的堆管理器感兴趣,请查看tcmalloc:http://goog-perftools.sourceforge.net/doc/tcmalloc.html
发布于 2011-09-18 12:02:11
我认为在一个新的重载中调用malloc()没有问题,只要确保你重载了delete,这样它就会调用free()。但是如果你真的不想调用malloc(),一种方法就是以另一种方式分配足够的内存:
class A {
public:
/* ... */
static void* operator new (size_t size) {
return (void *)new unsigned char[size];
}
static void operator delete (void *p) {
delete[]((unsigned char *)p);
}
/* ... */
};https://stackoverflow.com/questions/7459358
复制相似问题