【问题标题】:Which order should allocated memory blocks be freed in?分配的内存块应该按什么顺序被释放?
【发布时间】:2021-06-17 23:08:37
【问题描述】:

鉴于类似:

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

一旦你完成了内存块,这是正确的:

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

这是这样的:

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

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

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

【问题讨论】:

  • 理想情况下,按照拥有它们的智能指针被销毁的顺序。

标签: c++ c memory-management malloc


【解决方案1】:

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

假设:
如果释放内存的顺序对性能有影响,那么构建环境会更倾向于语言的总体趋势。

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

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

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

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

【讨论】:

    【解决方案2】:

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

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

    当一个类对象的数组被初始化(显式或隐式)并且元素被构造函数初始化时,应该为数组的每个元素调用构造函数,按照下标顺序;见dcl.array

    [注意 1:数组元素的析构函数按其构造的相反顺序调用。 — 尾注]

    【讨论】:

      【解决方案3】:

      我喜欢这样想,范围是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 ...,您将获得第二个选项。

      【讨论】:

        【解决方案4】:

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

        在我们的场景中,从第一个到最后一个释放几乎需要 4 分钟,而在另一个方向上只需要大约一分钟。

        但与性能一样,应在目标系统上衡量更改是否会产生任何影响。

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

            猜你喜欢
            • 2019-10-09
            • 1970-01-01
            • 2021-10-03
            • 1970-01-01
            • 2018-08-29
            • 2011-04-11
            • 2016-11-03
            • 1970-01-01
            • 2011-12-09
            相关资源
            最近更新 更多