分配的内存块应该按什么顺序释放?

Which order should allocated memory blocks be freed in?

给出类似的东西:

char *a = malloc(m);
char *b = malloc(n);
char *c = malloc(o);

完成内存块后,这是正确的:

free(a);
free(b);
free(c);

这也是:

free(c);
free(b);
free(a);

然而必须使用一个或另一个顺序,有一个选择的基础更令人满意。

是否有任何现有实现对内存碎片或释放内存和满足后续分配请求的速度有任何影响?如果是这样,哪种顺序更有效率?或者有没有其他选择顺序的依据?

在这些内存块之间没有任何已知关系的情况下,没有依据可以指定哪个释放顺序是正确的。正如没有依据可以决定哪个分配顺序是正确的。

这不是一个可以先验回答的问题。不释放内存的唯一原因是如果您仍在使用它,并且一块内存可能正在“使用”(即:将指针存储到)另一块内存。因此,在不知道该内存内部发生的事情的情况下,没有理由选择任何特定的释放顺序。

通常这与大多数用例无关。然而,我曾经有一个项目,它分配了非常多的对象,并且在那里产生了明显的性能差异。在这种情况下,第二个变体(从后到前)比按分配顺序释放要快得多。

在我们的场景中,从头到尾解除分配花费了将近 4 分钟,而在另一个方向上只花费了大约一分钟。

但与性能一样,更改是否会产生任何差异都应在目标系统上进行测量。

我喜欢这样想,有范围 ifs

    char *a = malloc(m);
    if (a) {
        char *b = malloc(n);
        if (b) {
            char *c = malloc(o);
            if (c) {
                //...
                free(c);
            }
            free(b);
        }
        free(a);
    }

现在,移除大括号和 ifs ...,您将获得第二个选项。

在其他条件相同的情况下,释放资源最好按照获取的相反顺序进行。这种“感觉”更自然,并且在某些情况下(包括内存 de/allocations)实际上可能更有效,因为对称性可以帮助所述资源的管理器更有序地回收它们。

这与例如 C++ 从头到尾构造数组元素,但以相反顺序破坏它们的原因相同 (class.init.general/3):

When an array of class objects is initialized (either explicitly or implicitly) and the elements are initialized by constructor, the constructor shall be called for each element of the array, following the subscript order; see dcl.array.

[Note 1: Destructors for the array elements are called in reverse order of their construction. — end note]

这是一个低级别的细节,可能会在您的构建环境升级时发生变化。因此,我会寻找一般原则而不是具体实施。在这种情况下,我会在一般原则中添加一个假设。

假设:
如果释放内存的顺序对性能有影响,对于语言的一般趋势,构建环境会更喜欢更好的性能。

这是基于构建环境重视生成快速程序的假设。任何想对此提出异议的人都应该忽略这个答案。

通过“语言的一般趋势”,我指的是最后构造的东西往往是最先破坏的东西。例如,派生 class 是在 之后 构造它的基础,但是派生 class 在 之前 它的基础被销毁.即使在 class 中,成员也会以相反的构造顺序销毁。最后建造,首先销毁。如果成员拥有动态分配的内存,则最后分配,最先释放(或多或少)。

这种趋势并不能保证内存会以获取的相反顺序释放。其实,想出反例并不难。然而,这确实意味着相反的顺序似乎比任何其他顺序更有可能。考虑到程序员可能会做的所有疯狂事情时,几乎没有什么保证,但对我来说 free 将以对称方式(顺序无关紧要)或以这种相反的顺序进行优化似乎是合理的,如果可能的话。

这不是证明,也不是绝对的规则。这只是在碰运气。如果以上看起来合理,我会建议最初使用语言的趋势。 (实际上,我建议在析构函数中释放内存,这会强制执行语言指定的顺序。)如果分析表明这是一个问题区域,则需要更多关注。在那之前,在问题的场景中,free(c) 首先提高你的几率。