【问题标题】:How do I mock memory allocation failures?如何模拟内存分配失败?
【发布时间】:2011-02-05 05:35:54
【问题描述】:

我想广泛测试一些 C 代码的内存泄漏。

在我的机器上,我有 4 Gb 的 RAM,因此动态内存分配不太可能失败。如果内存分配失败,我还是想看看代码的表现,看看恢复机制是否足够“强大”。

你有什么建议?如何模拟具有较低内存规格的环境?如何模拟我的测试?

编辑: 我希望我的测试独立于代码。我只有“访问权”来返回我正在测试的库中不同函数的值。我不应该在我正在测试的代码中编写“测试逻辑”。

【问题讨论】:

  • 代码独立是什么意思?
  • 如果它真的应该是代码独立的,那么这个问题不属于这里(关于服务器故障?)。您可以根据需要轻松设置具有尽可能少内存的 VM。
  • valgrind 不可用吗? Massif 是一个优秀的堆分析工具。

标签: c testing memory-leaks mocking memory-management


【解决方案1】:

制作一个包装器 malloc 并且免费,您可以将自己的逻辑放在那里以判断何时失败以及何时失败。

然后:

#define malloc(X) (myMalloc(X))
#define free(X) (myFree(X))
#define realloc(X, Y) (myRealloc(X, Y))
#define calloc(X, Y) (myCalloc(X, Y))
#define valloc(X) (myValloc(X))

您可以在整个代码中随意使用#define#undef 宏。

【讨论】:

  • ad 另一个问题是,如果内存占用非常小,它也可能是在堆限制之前达到的堆栈限制。因此,内存不足不一定发生在 malloc 上,但可能发生在任何通常有效的函数调用中...... :-(
【解决方案2】:

要独立执行此代码,我建议使用内存设置小得多的虚拟机并在其中运行您的代码。否则,您只能在内存配置较小的实际系统上进行测试。

【讨论】:

  • 1.您仍然有零机会测试所有可能的分配失败及其处理。
  • 您能否对此进行扩展,即您设想的分配失败的类别是什么?
  • 在单元测试代码中,我覆盖了所有标准的新建和删除操作。我可以设置下一次分配失败的大小,以及在返回失败之前应该处理多少分配。然后我进行正常的代码覆盖,看看我应该失败的分配。这种方式非常不稳定,但我想出的唯一一种。此外,仅仅拥有良好的代码覆盖率是一项完全无用的练习。当内存耗尽时,我所知道的所有系统都不会运行,除非发生泄漏,否则我正在处理的系统都不会耗尽内存。
【解决方案3】:

如果这是一个 unix 类型的系统,那么您可以做与 jemalloc 相同的事情。 实现自己的 malloc,将其编译为 .so -library 并使用 LD_PRELOAD=yourmalloc.so 开始测试

您可以构建一个允许您控制其运行方式的设置:

void tester() {
     your_malloc_allow_allocation(1024*1024*4); // allow 4 more megs of allocation

     librarycall();
     // ... handle errors..

     your_malloc_reset_limits(); // drop limits
}

【讨论】:

    【解决方案4】:

    当我不得不这样做的时候,我做了一个小程序,很快就用完了所有的内存。像这样的:

    // Beware, brain-compiled code ahead: 
    #include <stdlib.h>
    
    bool alloc(size_t n)
    {
        return NULL != malloc(n);
    }
    
    int main()
    {
        size_t n = 1;
        for(;;) {
            while( alloc(n) )
                n*=2;
            do
                n/=2;
            while( !alloc(n) );
        }
    }
    

    我对 Windows 的 NT 系列的经验是,虽然操作系统坚如磐石,但几乎所有其他东西都在我身上崩溃了,包括调试器。那样工作没有乐趣。

    【讨论】:

      【解决方案5】:

      输入 *(char*)0;当您希望代码失败或将其存储在分配的 var 中时

      (显然它应该通过makefile设置的一些#define来激活/停用)

      这个想法是精确控制你想要失败的 malloc。我使用前面的技巧来确保如果发生段错误,我编写的程序的行为会是什么。我能够检查异常是否被捕获,并且所有已分配的对象没有内存泄漏。

      您还可以添加某种计数器以使您的 alloc 仅在一段时间后返回 0 并检查您的代码是否正确处理这种情况(例如,正确释放程序选择销毁的部分以处理内存不足)。

      【讨论】:

      • 这有什么帮助?能具体点吗?
      • 当 malloc 失败时,它会这样做,返回 0... 你可以轻松伪造它。我不再多说。
      • 好吧,可能我描述的不够充分。但我希望我的测试独立于代码。
      • 如果您建议使用 #define 将 malloc 调用替换为 (char *)0,那么这将在第一次分配时失败,这不是很好的测试。
      • 这不是我要说的。我只是说在某些情况下您可以通过设置 0 来控制 malloc 行为。而且您可以准确控制要测试失败的 malloc。如果你设置一个全局包装器,你会测试一些东西,但不是一些非常受控制的东西,因为任何 malloc 都可能在程序的生命周期中失败。这很像猴子测试。我碰巧使用了前面的技巧来查看我的程序(多线程)在发生段错误时的行为。所以我真的自愿使用以前的技巧开始了一些段错误。
      【解决方案6】:

      禁用交换,然后在您的应用程序的开头执行while(malloc(1000000));

      这将使环境的可用内存不足 1MB,供您的应用程序的其余部分运行。调整其他结果的值。

      【讨论】:

        猜你喜欢
        • 2012-07-24
        • 2012-11-28
        • 2023-03-06
        • 2012-07-04
        • 1970-01-01
        • 2010-09-11
        • 2016-05-01
        • 2013-02-19
        • 2011-12-12
        相关资源
        最近更新 更多