C 高效内存再分配问题
假设我有一个程序(例如C++),它分配多个对象,永远不会超过给定的大小(我们称之为MAX_OBJECT_size) 我在堆上也有一个区域(我称之为“页面”)(分配有malloc(region\u SIZE),其中region\u SIZE>=MAX\u OBJECT\u SIZE)。C 高效内存再分配问题,c,memory-management,performance,malloc,realloc,C,Memory Management,Performance,Malloc,Realloc,假设我有一个程序(例如C++),它分配多个对象,永远不会超过给定的大小(我们称之为MAX_OBJECT_size) 我在堆上也有一个区域(我称之为“页面”)(分配有malloc(region\u SIZE),其中region\u SIZE>=MAX\u OBJECT\u SIZE)。 我一直在那个页面中保留空间,直到填充的空间等于页面大小(或者至少得到>页面大小-最大对象大小) 现在,我想分配更多内存。显然,我以前的“页面”是不够的。所以我至少有两个选择: 使用realloc(页面,新大小),其
我一直在那个页面中保留空间,直到填充的空间等于页面大小(或者至少得到>页面大小-最大对象大小) 现在,我想分配更多内存。显然,我以前的“页面”是不够的。所以我至少有两个选择:
我知道不同的操作可能会执行不同的操作,但我正在寻找一个总体指标。从您的问题中不清楚为什么需要提前分配一大块内存,而不是根据需要为每个对象分配内存。我假设您将其用作连续数组。否则,根据需要对每个对象的内存进行
malloc
如果它确实起到数组的作用,malloc
-调用另一个块将为您提供另一块内存,您必须通过另一个指针访问它(在您的例子中是page2
)。因此,它不再位于连续块上,并且不能将这两个块用作一个数组的一部分
另一方面,realloc
,分配一个连续的内存块。您可以将其用作单个数组,并执行各种指针运算,如果存在单独的块,则不可能执行这些运算realloc
在您确实想要缩小正在使用的块时也很有用,但这可能不是您在这里想要做的
因此,如果将其用作数组,
realloc
基本上是更好的选择。否则,malloc
就没有问题了。实际上,您可能希望为您创建的每个对象使用malloc
,而不必跟踪和微管理内存块。您还没有给出您正在试验的平台的任何详细信息。例如,Linux
和Windows
之间的realloc
有一些性能差异
根据情况,realloc
如果不能增加当前内存块,并且将旧内存复制到新内存块,则可能必须分配一个新内存块,这是非常昂贵的。
如果您真的不需要连续的内存块,则应避免使用realloc
我的建议是使用第二种方法,或者使用自定义分配器(您可以实现一个简单的方法)
您还可以使用更高级的内存分配器,如
realloc
将被malloc方法“击败”,但要说失败的程度,您应该进行测试(我认为在内存请求完成时,系统的运行方式存在偏差)
根据需要执行realloc/malloc的次数,它可能是一个有用的想法,也可能是一个无用的想法。无论如何,我都会使用malloc
自由战略取决于实施情况。要将所有页面作为一个整体释放,只需“遍历”它们就足够了;我不使用数组,而是使用链接的“页面”:将sizeof(void*)添加到“页面”大小,您可以使用额外的字节来存储指向下一页的指针
如果您必须释放位于其中一个页面中任意位置的单个对象,它会变得稍微复杂一些。我的想法是保留一个非顺序自由“块”/“槽”(适合容纳任何对象)的列表。当请求新的“块”时,首先从该列表中弹出一个值;如果它是空的,那么您将在最后一个正在使用的页面中获得下一个“插槽”,并最终触发一个新页面。释放一个对象,意味着只需将空插槽地址放入堆栈/列表中(无论您喜欢使用什么)。根据我的经验,选项2更容易使用,开销最小。Realloc不保证它会增加现有内存的大小。在实践中,它几乎从来没有这样做过。如果使用它,则需要返回并重新映射所有旧对象。这需要你记住每个分配的对象在哪里。。。那可能比头顶高出一吨 但如果不确切知道您使用的指标,就很难确定“最有效” 这是我经常使用的内存管理器。它适用于整个应用程序,而不仅仅是一个对象 allocs: 对于每个分配,确定分配对象的大小 1查看该大小对象的空闲链接列表,查看是否有任何内容已被释放,如果是,请获取第一个空闲 2在查找表中查找,如果未找到 2.1分配一个由N个被分配大小的对象组成的数组 3返回所需大小的下一个自由对象 3.1如果阵列已满,请添加新页面 N个对象可以是p