使用 Instruments 检测 C/C++ 命令行内存泄漏

4

我正在尝试在macOS上检测C(和C ++)程序中的内存泄漏。在Linux和Windows上,我可以使用valgrind轻松地执行此操作,但不幸的是,在macOS上无法使用。

由于我具有ObjC和iOS开发的背景经验,我想使用Instruments进行内存泄漏检查。乍一看,它似乎非常适合这项工作。

我编写了这个非常简单的泄漏程序:

#include <stdlib.h>
#include <stdio.h>

int* allocSomething() {
  return malloc(sizeof(int));
}

int main(int argc, const char * argv[]) {
  int* p = allocSomething();
  *p = 5;
  printf("*p = %d\n", *p);
  p = NULL;
  return 0;
}

我使用了Clang静态分析器来检测代码,但我也想在Instruments中捕获它,因为我正在寻找一个合适的Valgrind替代品。因此:

  • 我将Profile模式更改为使用Debug而不是Release。
  • 我确保没有优化。

然而,在使用Instruments之后: Instruments does not detect leaks

正如您所看到的,没有泄漏报告。 在网上搜索后,我发现了Can't detect C leaks in xcode 9 instruments,其中作者使用了sleep,因此我认为Instruments实际上并没有像Valgrind一样覆盖malloc,而是使用采样技术,并且它不能在这么短的时间内进行采样,因此我将程序更改为:

int main(int argc, const char * argv[]) {
  int* p = allocSomething();
  p = NULL;
  sleep(600000);
  return 0;
}

现在我明白了:

完全没有泄漏

这完全没有意义,因为它是一个明显的内存泄漏。 我认为这可能与优化有关,但是我已经明确地禁用了它。此外,如果我malloc更多的字节,它会检测到。或者这可能是Instruments的一个bug吗?

所以我想知道这是否是Instruments无法检测到小内存分配的问题?需要注意的是,Valgrind可以很好地处理它,所以我感到惊讶。

你有什么建议吗?

1个回答

5
Leaks模板中的Leak工具与您预期的不同。首先,它无法检测短暂进程中的任何内容:它是基于计时器的。它会定期停止进程并检查其泄漏情况。对于短暂的进程,在进程退出之前永远不会进行检查。其次,它可能会错过一些泄漏:它会检查所有线程的堆栈、所有线程的寄存器和全局变量,以查找分配的地址。如果在任何地方找到了分配的地址,则不认为该分配已泄漏。在您的情况下,分配的地址可能仍然在寄存器或堆栈内存中。在“真正”的程序中,堆栈和寄存器最终会被重用,并且这样的陈旧数据将被消除。Allocations工具确实跟踪所有分配和释放(假设进程是由Instruments启动的)。您的泄漏分配位于分配列表中,并且仍然列为“活动”(即已创建和持久)。问题在于Allocations工具没有明确指出这样的分配是否泄漏。
此外,系统库还进行了一些分配,旨在生存到进程退出并且未被明确清除。因此,您的泄漏有点深藏在无关信息中。您可以对分配列表进行过滤和排序以发现泄漏,但这需要一些操作。
在更真实的程序环境中,Instruments非常擅长查找泄漏。
显然,Clang支持LeakSanitizer,可以作为AddressSanitizer或独立存在的一部分。这可能需要一个比苹果作为Xcode和/或Catalina的一部分提供的版本更新的Clang版本。(我在Mojave上使用Xcode 11.3.1进行测试。它不支持-fsanitize=leak选项,也不支持ASAN_OPTIONS=detect_leaks=1)。假设您可以让它正常工作,那么它可能会更像您所期望的那样运行。

感谢您的详细解释!我会使用Clang sanitizer! - OzB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接