C++ 使用多个堆进行内存管理有什么好处吗?

C++ 使用多个堆进行内存管理有什么好处吗?,c++,winapi,memory-management,C++,Winapi,Memory Management,我是一名系统软件系的学生。现在我正在为Windows开发一个内存管理器。下面是我对malloc()和free()的简单实现: 它很好用。但是我不明白为什么要使用多个堆?我可以在堆中分配内存,并将地址分配给分配的内存块。但是这里我使用了一个堆。是否有理由使用多个堆?可能适用于多线程/多进程应用程序?请解释。使用多堆/自定义分配器的主要原因是为了更好地控制内存。通常,在大量新建/删除后,应用程序的内存会变得支离破碎,性能下降(应用程序也会消耗更多内存)。在更受控的环境中使用内存可以减少堆碎片 另一个

我是一名系统软件系的学生。现在我正在为Windows开发一个内存管理器。下面是我对
malloc()
free()
的简单实现:


它很好用。但是我不明白为什么要使用多个堆?我可以在堆中分配内存,并将地址分配给分配的内存块。但是这里我使用了一个堆。是否有理由使用多个堆?可能适用于多线程/多进程应用程序?请解释。

使用多堆/自定义分配器的主要原因是为了更好地控制内存。通常,在大量新建/删除后,应用程序的内存会变得支离破碎,性能下降(应用程序也会消耗更多内存)。在更受控的环境中使用内存可以减少堆碎片

另一个用途是防止应用程序中的内存泄漏,您只需释放分配的整个堆,而无需释放在那里分配的所有对象

另一种用法是用于紧密分配的对象,例如,如果您有一个列表,那么您可以在一个较小的专用堆中分配所有节点,应用程序将获得性能,因为在迭代节点时,缓存未命中的次数会更少


编辑:然而,内存管理是一个很难的话题,在某些情况下,它做得不对。Andrei Alexandrescu在一次谈话中说,对于某些应用程序,用默认分配器替换自定义分配器可以提高应用程序的性能。

原因之一是您需要在内部执行程序,例如运行模拟代码。通过创建自己的堆,您可以允许该堆具有执行权限,出于安全原因,默认情况下该权限是关闭的。(Windows)

你有一些好的想法,这对C来说是有效的,但是C++中有析构函数,它们运行非常重要。 您可以认为所有类型都有构造函数/析构函数,只是在逻辑上“什么都不做”

这是关于分配器的。请参阅“好友算法”,它使用二的幂来对齐和重用内容

如果我在某个地方分配4个字节,我的分配器可能只为4个字节分配一个4kb的部分。这样,我可以在块中容纳1024个4字节的内容,如果需要更多,请添加另一个块,以此类推

如果请求4kb,它不会在4byte块中分配,它可能会为更大的请求分配一个单独的块


这意味着你可以把大事放在一起。如果我使用17个字节,然后是13个字节,1个字节和13个字节被释放,我只能把一些东西放在那里我唯一一次使用多个堆是在我编写一个程序构建复杂的数据结构时。通过遍历数据结构并释放各个节点来释放数据结构本来是不容易的,但幸运的是,对于我来说,程序只是暂时需要数据结构(当它执行特定操作时),所以我对数据结构使用了单独的堆,这样当我不再需要它时,我可以通过一次调用HeapDestroy来释放它。

这是一个很好的链接,详细说明了为什么您可能需要多个堆:


只是好奇,如果这是你的实现,你不知道为什么要创建3吗?我刚刚测试了一些东西。它会引起一些问题吗?是的,请看我的答案。你使用C++而不是C,你必须确保析构函数被调用。MALC/C/FILE通常自动创建/释放堆以减少碎片吗?你不能仅仅“删除堆”——你可以释放它,但你不应该。delete使用析构函数(除了free之外,它不是void*的函数),如果你删除了一个巨大的线束,但没有破坏其中的东西,那么如果你有容器结构之类的东西,它们可能会有指向其他堆的指针。他说C++,“防止内存泄漏”-就是questionable@AlecTeal我更改了“删除”选项,但在那里不合适。@Dieter Lücking是的,这是在游戏中经常做的,不仅仅是小游戏,Tripa A游戏使用这样的技术。你仍然不应该只是删除它,我认为你把分配器和区域混淆了。这对我帮助很大。我理解你的建议,并向老师解释了。他同意了。
HANDLE heap = HeapCreate(0, 0, 0);

void* hmalloc(size_t size)
{
    return HeapAlloc(heap, 0, size);
}

void hfree(void* memory)
{
    HeapFree(heap, 0, memory);
}

int main()
{
    int* ptr1 = (int*)hmalloc(100*sizeof(int));
    int* ptr2 = (int*)hmalloc(100*sizeof(int));
    int* ptr3 = (int*)hmalloc(100*sizeof(int));

    hfree(ptr2);
    hfree(ptr3);
    hfree(ptr1);

    return 0;
}
"Why Use Multiple Heaps?
Using a single runtime heap is fine for most programs. However, using multiple 
heaps can be more efficient and can help you improve your program's performance 
and reduce wasted memory for a number of reasons:

1- When you allocate from a single heap, you may end up with memory blocks on
   different pages of memory. For example, you might have a linked list that 
   allocates memory each time you add a node to the list. If you allocate memory for
   other data in between adding nodes, the memory blocks for the nodes could end up
   on many different pages. To access the data in the list, the system may have to 
   swap many pages, which can significantly slow your program.

   With multiple heaps, you can specify which heap you allocate from. For example, 
   you might create a heap specifically for the linked list. The list's memory blocks 
   and the data they contain would remain close together on fewer pages, reducing the 
   amount of swapping required.

 2- In multithread applications, only one thread can access the heap at a time to 
    ensure memory is safely allocated and freed. For example, say thread 1 is 
    allocating memory, and thread 2 has a call to free. Thread 2 must wait until 
    thread 1 has finished its allocation before it can access the heap. Again, this 
    can slow down performance, especially if your program does a lot of memory 
    operations.

    If you create a separate heap for each thread, you can allocate from them 
    concurrently, eliminating both the waiting period and the overhead required to 
    serialize access to the heap.


 3- With a single heap, you must explicitly free each block that you allocate. If you 
    have a linked list that allocates memory for each node, you have to traverse the 
    entire list and free each block individually, which can take some time.

    If you create a separate heap for that linked list, you can destroy it with a 
    single call and free all the memory at once.

  4- When you have only one heap, all components share it (including the IBM C and 
     C++ Compilers runtime library, vendor libraries, and your own code). If one 
     component corrupts the heap, another component might fail. You may have trouble 
     discovering the cause of the problem and where the heap was damaged.

     With multiple heaps, you can create a separate heap for each component, so if 
     one damages the heap (for example, by using a freed pointer), the others can 
     continue unaffected. You also know where to look to correct the problem."