理解"泄漏"命令行实用程序以查找内存泄漏

5 iphone cocoa cocoa-touch memory-leaks objective-c

我正在努力追踪我的iPhone程序中一些难以发现的内存泄漏.我正在对一个泄漏NSString对象的应用程序进行快速测试,其中包含以下故意 - 不正确的代码:

-(void)applicationDidFinishLaunching:(NSNotification *)notification;
{
    NSMutableString *test = [[NSMutableString alloc] init];
    [test appendString:@"Testing 1"];
    [test appendString:@"\nTesting 2"];
    NSLog(@"%@", test);

    // Uncomment the following line to release the
    // string and clean up your leak.
    // [test release], test = nil;
}
Run Code Online (Sandbox Code Playgroud)

在对应用程序的进程ID运行泄漏后,我想出了以下内容:

sf$ leaks 3951
Process 3951: 9988 nodes malloced for 1260 KB
Process 3951: 3 leaks for 128 total leaked bytes.
Leak: 0x163b50  size=64 instance of 'NSCFDictionary', type ObjC, implemented in Foundation  
    0xa07e0720 0x01001080 0x0000000a 0x00000010      .~.............
    0x0000000a 0x0000000c 0x0000000b 0x00000000     ................
    0x00000000 0x00000015 0xa1b1c1d3 0x00163b90     .............;..
    0x00163bd0 0x00000000 0x00000000 0x00000000     .;..............
Leak: 0x178190  size=32 string 'Testing 1
Testing 2'
Leak: 0x178210  size=32 instance of 'NSCFString', type ObjC, implemented in CoreFoundation  
    0xa02e24a0 0x010007ad 0x00178190 0x00000013     .$..............
    0x00000020 0x00000200 0x00000000 0x00000000      ...............
Run Code Online (Sandbox Code Playgroud)

现在,我们都知道泄漏的位置.至少对我来说,这不是这个练习的重点.我正在努力识别如何理解这个输出.我被告知有3次泄漏.

它们是位于存储器地址0x163b50,0x178190,0x178210的对象.他们的实现是在Apple框架中,而不是我的代码 - 根据'泄漏'.在诸如以下的简单示例中,找到泄漏并不困难.但是,在具有500K代码行的应用程序中,我发现泄漏的输出在这里毫无用处.

我做错了什么,如何理解这个输出,以帮助我找到我编写的代码中的罪魁祸首来清理我的内存泄漏?

请注意,该主题不应提倡使用Instruments或Clang Static Analyzer.我已经清理了Clang Static Analyzer向我报告的所有内存泄漏.仪器臃肿,对我没有信息.我收到大量关于泄漏的报告,没有一个堆栈跟踪显示回到我自己的代码 - 虽然我确定泄漏确实在我的代码中.我想在这里弄清楚如何使用cmd线泄漏工具.

谢谢大家.

编辑:即使在取消注释线以清理泄漏之后,"泄漏"实用程序的抱怨甚至比泄漏时更多.基金会/可可从这样一个微不足道的例子中泄漏了多少?在取消注释上面的测试字符串的发布后会发生这种情况:

sf$ leaks 4383
Process 4383: 9890 nodes malloced for 1255 KB
Process 4383: 7 leaks for 560 total leaked bytes.
Leak: 0x163920  size=176    instance of 'NSPathStore2', type ObjC, implemented in Foundation    
    0xa07e2ae0 0x04f00000 0x0055002f 0x00650073     .*~...../.U.s.e.
    0x00730072 0x0073002f 0x002f0066 0x0069004c     r.s./.s.f./.L.i.
    0x00720062 0x00720061 0x002f0079 0x00700041     b.r.a.r.y./.A.p.
    0x006c0070 0x00630069 0x00740061 0x006f0069     p.l.i.c.a.t.i.o.
    0x0020006e 0x00750053 0x00700070 0x0072006f     n. .S.u.p.p.o.r.
    0x002f0074 0x00490053 0x0042004d 0x002f004c     t./.S.I.M.B.L./.
    0x006c0050 0x00670075 0x006e0069 0x002f0073     P.l.u.g.i.n.s./.
    0x00650054 0x006d0072 0x006e0069 0x006c0061     T.e.r.m.i.n.a.l.
    ...
Leak: 0x163350  size=160    instance of 'NSPathStore2', type ObjC, implemented in Foundation    
    0xa07e2ae0 0x04a00000 0x0055002f 0x00650073     .*~...../.U.s.e.
    0x00730072 0x0073002f 0x002f0066 0x0069004c     r.s./.s.f./.L.i.
    0x00720062 0x00720061 0x002f0079 0x00700041     b.r.a.r.y./.A.p.
    0x006c0070 0x00630069 0x00740061 0x006f0069     p.l.i.c.a.t.i.o.
    0x0020006e 0x00750053 0x00700070 0x0072006f     n. .S.u.p.p.o.r.
    0x002f0074 0x00490053 0x0042004d 0x002f004c     t./.S.I.M.B.L./.
    0x006c0050 0x00670075 0x006e0069 0x002f0073     P.l.u.g.i.n.s./.
    0x00650044 0x0069006c 0x00690063 0x0075006f     D.e.l.i.c.i.o.u.
    ...
Leak: 0x1635a0  size=64 instance of 'NSCFDictionary', type ObjC, implemented in Foundation  
    0xa07e0720 0x01001080 0x0000000a 0x00000010      .~.............
    0x0000000a 0x0000000c 0x0000000b 0x00000000     ................
    0x00000000 0x00000015 0xa1b1c1d3 0x001635e0     .............5..
    0x00163620 0x00000000 0x00000000 0x00000000      6..............
Leak: 0x163620  size=64 
    0xa02ed360 0x00160ee0 0x00163700 0xa02efc00     `........7......
    0x00000000 0x00000000 0x00163680 0x00000000     .........6......
    0x00000000 0x00000000 0x00163660 0xa02ed440     ........`6..@...
    0xa02ec1a0 0xa02f0420 0x00000000 0x00163660     .... ./.....`6..
Leak: 0x163680  size=48 instance of 'NSCFString', type ObjC, implemented in CoreFoundation  
    0xa02e24a0 0x0100078c 0x6d6f6323 0x6c65642e     .$......#com.del
    0x6f696369 0x61737375 0x69726166 0x6c65442e     icioussafari.Del
    0x6f696369 0x61537375 0x69726166 0x00000000     iciousSafari....
Leak: 0x163660  size=32 instance of 'NSCFString', type ObjC, implemented in CoreFoundation  
    0xa02e24a0 0x0200078c 0x6c65440f 0x6f696369     .$.......Delicio
    0x61537375 0x69726166 0x00000000 0x00000000     usSafari........
Leak: 0x160ee0  size=16 instance of 'NSCFString', type ObjC, implemented in CoreFoundation  
    0xa02e24a0 0x0100078c 0x362e3103 0x00000000     .$.......1.6....
Run Code Online (Sandbox Code Playgroud)

Pet*_*sey 4

您显示的输出中没有堆栈跟踪。您看到的地址是对象自己的地址,而不是函数指针,标点符号旁边的十六进制数字\xc2\xa0 只是数据的十六进制转储。

\n\n

要找出对象是哪里分配的,请在泄漏的环境中设置 MallocStackLogging:

\n\n
% MallocStackLogging=1 leaks \xe2\x80\xa6\n
Run Code Online (Sandbox Code Playgroud)\n\n

您可能还想使用 -nocontent 选项,这将抑制十六进制转储。但是,不要一直使用它:有时十六进制转储包含有价值的线索。

\n\n

另外,泄漏并不一定告诉您有 3 个泄漏;准确地说,它告诉您有三个泄漏的对象。您展示的故意泄漏仅产生一个泄漏对象,但不同的泄漏(例如在循环或频繁调用的方法中)可能会泄漏许多对象。

\n\n

编辑:顺便说一句,其中一些泄漏来自 SIMBL 或您的一个或多个 SIMBL 插件。在查找泄漏之前,请关闭 SIMBL 和任何其他输入管理器 hack。请记住,该代码在您的进程中运行;而且,leaks 并不关心谁的代码分配或泄漏了内存,只关心内存被泄漏,因此无论谁分配或泄漏了内存,它都会显示泄漏的对象。

\n