【问题标题】:bring malloc() back to its initial state将 malloc() 带回其初始状态
【发布时间】:2010-12-27 05:50:36
【问题描述】:

你知道是否有办法让 malloc 恢复到初始状态,就像程序刚刚启动一样?

原因:我正在使用 nintendods devkitpro 开发嵌入式应用程序,我希望能够在出现软件故障时改进调试支持。我已经可以捕捉到大多数错误,例如返回控制台菜单,但在捕获 std::bad_alloc 时无法正常工作。

我怀疑我用于“软重启”的代码在某些时候我无法控制涉及 malloc() 本身,所以我想“忘记正在运行的应用程序的所有内容并重新开始”。

【问题讨论】:

  • 顺便说一句,我正在使用的 malloc 实现有 malloc_stats 和 mallinfo,但没有 malloc_set_state 或 malloc_get_state 可能(?)提供了解决方案。
  • 看起来我的 devkit 正在使用“newlib”的分配器。我会研究这个以找出一个更好的方法来调查这个问题。

标签: c++ exception-handling malloc nintendo-ds devkitpro


【解决方案1】:

没有办法以可移植的方式执行此操作,尽管可以想象 C++ 的嵌入式实现可能会将其作为扩展提供。相反,您应该考虑编写自己的分配系统、使用内存池或使用现有库。

【讨论】:

    【解决方案2】:

    只有在我做类似的事情时,我们使用了自己的分配器,它会保留对每个分配块的引用。如果我们想回滚,我们将释放所有分配的块并执行 longjmp 以重新启动程序。

    【讨论】:

      【解决方案3】:

      在全局位置释放一点内存,例如

      int* not_used = new i[1024];
      

      然后,当您收到 std::bad_alloc 时,删除 not_used 并转到您的错误控制台。这个想法是给你的崩溃处理程序足够的空间来做你需要的事情。您必须调整保留多少内存,以免您的控制台也收到内存不足错误。

      如果你够聪明,实际上可以使用 not_used。但是你必须小心,任何正在使用内存的东西都可能在不通知的情况下被删除。

      【讨论】:

      • 好主意。这将需要一些调整,因为我忽略了需要在哪里以及需要多少内存,但是如果我设法找出来,它就可以解决问题。不过,我不太确定 缺少 内存是问题的根源。恐怕一些缓冲区溢出也会破坏 malloc 的内部状态。
      【解决方案4】:

      重新开始的唯一方法是从存储中重新加载应用程序。 DS 将所有内容加载到 RAM 中,这意味着数据部分已就地修改。

      【讨论】:

      • ... 这反过来又强调了一个事实,即从存储中加载应用程序到 RAM 中永远不应该使用 malloc() ...
      【解决方案5】:

      我想如果没有其他东西正在运行,您可以将 API 在 Nintendo 上提供的整个内存块写入零吗?但除此之外,只需跟踪您的分配。

      事实上,如果您创建一个CatchAndRelease 类来保留对每个分配的内存块的引用,那么您可以在需要的时间返回并清除它们。

      否则,您可能需要编写自己的内存池,如 Neil 所述。

      【讨论】:

        【解决方案6】:

        除了后进先出的顺序之外,您是否需要释放内存?如果没有,我建议您定义一个数组以使用所有可用内存(您可能必须调整链接器文件来执行此操作),然后初始化指向该数组开头的指针。然后编写自己的 malloc() 函数:

        char *allocation_ptr = big_array; 无效 *malloc(size_t n) { void *temp = (void*)allocation_ptr; if (allocation_ptr > END_OF_ALLOCATION_AREA - n) 返回0; 分配_ptr += n; 返回温度; } void free_all_after(void *ptr) { 如果(指针) 分配_ptr = (char*)ptr; }

        在这个实现中,free_all_after() 将释放指定的指针以及在它之后分配的所有内容。请注意,与 malloc() 的其他实现不同,此实现具有 开销。 LIFO 分配非常有限,但对于许多嵌入式系统来说已经足够了。

        【讨论】:

        • 是的,很遗憾我无法将内存分配简化到这一点。
        • @sylvainulg:这种内存管理方法适用于某些工作,但不是全部。一个细微的变化是有一块从顶部和底部分配的内存(在这种情况下,可以独立地从顶部和底部进行 LIFO 释放)。第三种变体(用于 1980 年代微型计算机 BASIC 解释器)如果很容易找到所有指向内存的指针(使用双间接指针可以帮助解决此问题)是使用垃圾压缩而不是空闲列表。这种方法有局限性,但可以避免碎片化。
        【解决方案7】:

        std::bad_alloc 在 new 失败并且无法分配请求的内存时发生。这通常会在堆内存不足并因此无法满足请求时发生。因此,您将无法在清理过程中可靠地分配任何新内存。

        这意味着您不能分配新的内存进行清理。成功清理的唯一希望是确保在实际需要之前为清理代码预先分配内存。

        仍然可以使用 inplace new 运算符将对象更新到此清理内存中(即在您提供内存地址的地方新建)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-02-09
          • 2021-08-26
          • 1970-01-01
          • 2020-08-31
          • 1970-01-01
          • 2019-05-08
          相关资源
          最近更新 更多