简体   繁体   English

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

[英]Detect C/C++ command line memory leaks using Instruments

I'm trying to detect memory leaks in C (and C++) programs on macOS.我正在尝试检测 macOS 上 C(和 C++)程序中的 memory 泄漏。 In Linux and Windows, I could do so easily using valgrind , but unfortunately, it's not available on macOS.在 Linux 和 Windows 中,我可以使用valgrind轻松做到这一点,但不幸的是,它在 macOS 上不可用。

As I have background experience with ObjC and iOS dev, I thought to use Instruments to do the memory leak check.由于我有 ObjC 和 iOS 开发的背景经验,我想使用 Instruments 来进行 memory 泄漏检查。 At first glance, it sounded perfect for the job.乍一看,这听起来很适合这份工作。

I wrote this very simple leaked program:我写了这个非常简单的泄露程序:

#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;
}

I ran it through Clang Static Analyzer which did the job, but I wanted it to be caught in Instruments as well because I'm looking for a proper Valgrind replacement.我通过 Clang Static Analyzer 运行它,它完成了这项工作,但我希望它也能被 Instruments 捕获,因为我正在寻找合适的 Valgrind 替代品。 Thus:因此:

  • I changed the Profile schema to use Debug instead of Release.我将 Profile 架构更改为使用 Debug 而不是 Release。
  • I made sure there are no optimizations.我确保没有优化。

However, after using Instruments:但是,使用 Instruments 后: 仪器未检测到泄漏

and as you can see, no leak reported.如您所见,没有报告泄漏。 After searching online, I came across Can't detect C leaks in xcode 9 instruments , in which the author used sleep , so I thought maybe Instruments doesn't actually override malloc as Valgrind, but use a sampling technique, and it doesn't sample it in such short notice, so I changed the program into:在网上搜索后,我在 xcode 9 个仪器中遇到 Can't detect C leaks ,其中作者使用了sleep ,所以我想可能 Instruments 实际上并没有覆盖malloc采样技术,而是使用了 agrind 采样技术,在这么短的时间内对其进行采样,因此我将程序更改为:

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

Now, I get:现在,我得到: 完全没有泄漏

Which totally doesn't make sense, as it's an obvious memory leak.这完全没有意义,因为这是一个明显的 memory 泄漏。 I'd say that it has to do something with optimization, but then again I disabled it explicitly.我会说它必须做一些优化,但我又一次明确地禁用了它。 In addition, if I malloc more bytes, it does detect it.另外,如果我malloc更多字节,它确实检测到它。 Or maybe it's a bug in Instruments?或者可能是仪器中的错误?

So I wonder if it's an issue with Instruments that can't detect small allocations?所以我想知道这是否是仪器无法检测到小分配的问题? I must note that Valgrind can deal with it very well so I'm surprised.我必须指出,Valgrind 可以很好地处理它,所以我很惊讶。

Do you got any suggestions?你有什么建议吗?

The Leaks instrument (one of the instruments in the Leaks template) works differently than you're expecting. Leaks 工具(Leaks 模板中的一种工具)的工作方式与您的预期不同。

First, why it doesn't detect anything for short-lived processes: it is timer-based.首先,为什么它不会检测任何短期进程:它是基于计时器的。 It stops the process every so often and checks it for leaks.它每隔一段时间就会停止该过程并检查它是否存在泄漏。 For a short-lived process, the check never happens before the process exits.对于一个短暂的进程,检查永远不会在进程退出之前发生。

Second, why it can miss some leaks: it examines the stacks of all threads, the registers for all threads, and global variables looking for the addresses of allocations.其次,它为什么会漏掉一些泄漏:它检查所有线程的堆栈、所有线程的寄存器以及寻找分配地址的全局变量。 If an allocation's address is found in any of those places, that allocation is not considered to have leaked.如果在这些位置中的任何一个找到分配的地址,则该分配不被视为已泄漏。

In your case, the address of the allocation is probably still in a register or stack memory.在您的情况下,分配的地址可能仍在寄存器或堆栈 memory 中。 In a "real" program, the stack and registers would eventually be reused and such stale data would be eliminated.在“真正的”程序中,堆栈和寄存器最终会被重用,并且这些陈旧的数据将被消除。

The Allocations instrument does track all allocations and deallocations (assuming the process was launched by Instruments). Allocations 工具确实跟踪所有分配和解除分配(假设该过程由 Instruments 启动)。 Your leaked allocation is in the allocation list and still listed as "live" (aka Created & Persistent).您泄露的分配在分配列表中,并且仍然列为“实时”(又名创建和持久)。 The problem is that the Allocations instrument does not explicitly call out such allocations as leaks.问题是 Allocations 工具没有明确地将此类分配称为泄漏。

In addition, the system libraries have also made allocations that are intended to survive until process exit and are not cleaned up explicitly.此外,系统库还进行了旨在保留到进程退出并且没有明确清理的分配。 So, your leak is a bit buried in irrelevant information.因此,您的泄漏有点隐藏在不相关的信息中。 You can filter and sort the allocation list to uncover your leak, but it takes some doing.您可以过滤和排序分配列表以发现您的泄漏,但这需要做一些事情。

In the context of a more real program, Instruments is quite good at finding leaks.在更真实的程序的上下文中,Instruments 非常擅长发现泄漏。

Apparently, Clang supports a LeakSanitizer , either as part of the AddressSanitizer or standalone.显然, Clang 支持LeakSanitizer ,作为 AddressSanitizer 的一部分或独立。 That may require a version of Clang that's newer than what Apple ships as part of Xcode and/or Catalina.这可能需要一个比 Apple 作为 Xcode 和/或 Catalina 的一部分提供的版本更新的 Clang 版本。 (I tested with Xcode 11.3.1 on Mojave. It doesn't support the -fsanitize=leak option and ASAN_OPTIONS=detect_leaks=1 wasn't supported either.) Assuming you can get that to work, that might behave more like what you're expecting. (我在 Mojave 上使用 Xcode 11.3.1 进行了测试。它不支持-fsanitize=leak选项,也不支持ASAN_OPTIONS=detect_leaks=1 。)假设你可以让它工作,那可能更像你'期待。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM