了解iOS泄漏调用堆栈跟踪

时间:2012-11-14 14:23:46

标签: objective-c ios ios5 malloc memory-leaks

当我使用以下命令调用泄漏时,我有以下malloc堆栈跟踪:

MallocStackLogging = 1泄漏

泄漏:0x15d3cac0 size = 256 zone:DefaultMallocZone_0x7b0a000

Call stack: [thread 0xb0468000]: | thread_start | _pthread_start | __NSThread__main__ | -[NSThread main] | -[AggregatorObjCWorkQueue newThreadMainLoop] | -[NSRunLoop(NSRunLoop) runMode:beforeDate:] | CFRunLoopRunInMode | CFRunLoopRunSpecific | __CFRunLoopRun | __CFRunLoopDoSources0 | __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ | __NSThreadPerformPerform | -[NSObject performSelector:withObject:] | -[AggregatorTask run] | -[ComAppAggregatorApiSystemClientWorkerFactory_$4_$1 run] | -[ComAppAggregatorFrameworkClientSubscriptionSyncer startWithComAppAggregatorApiClient:] | -[ComAppAggregatorSyncClientSyncSubscriptionRegistry addSubscriptionWithComAppAggregatorQueryQueryXML_Subscription:] | -[ComAppAggregatorSyncClientSyncSubscriptionRegistry newSyncAndPostWithComAppAggregatorQueryQueryXML_QueryKey:] | -[ComAppAggregatorSyncClientSyncSubscriptionRegistry writeUpdateWithComAppAggregatorQueryQueryXML_QueryKey:] | -[ComAppAggregatorSyncClientSyncSubscriptionRegistry writeSubscriptions] | -[JavaUtilTreeMap putWithId:withId:] TreeMap.m:371 | -[JavaUtilTreeMap createNodeWithId:withId:] TreeMap.m:634 | -[JavaUtilTreeMap_Node init] TreeMap.m:1463 | -[IOSObjectArray initWithLength:type:] IOSObjectArray.m:42 | calloc | malloc_zone_calloc

有人可以帮我理解来自malloc的这个调用堆栈跟踪吗? 即打破这个问题: 1.如何排序堆栈跟踪? Class1 Method1 | Class2 Method2 | Class3方法3: 这些意味着什么?

2:对象描述前的正负号是什么意思? - [类方法] | + [课程方法]

3:其中哪一个实际上是泄漏的? 我无法准确确定堆栈跟踪的哪个对象/部分正在泄漏。

任何指向文档的链接都会很棒!

2 个答案:

答案 0 :(得分:5)

使用Leaks仪器(在“仪器”应用程序中)查看“扩展详细信息”窗格中的堆栈跟踪要容易得多。

但是这里是分析堆栈跟踪的方法。首先,用换行符替换|的每个实例:

Call stack: [thread 0xb0468000]: 
thread_start 
_pthread_start 
__NSThread__main__ 
-[NSThread main] 
-[AggregatorObjCWorkQueue newThreadMainLoop] 
-[NSRunLoop(NSRunLoop) runMode:beforeDate:] 
CFRunLoopRunInMode 
CFRunLoopRunSpecific 
__CFRunLoopRun 
__CFRunLoopDoSources0 
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ 
__NSThreadPerformPerform 
-[NSObject performSelector:withObject:] 
-[AggregatorTask run] 
-[ComAppAggregatorApiSystemClientWorkerFactory_$4_$1 run] 
-[ComAppAggregatorFrameworkClientSubscriptionSyncer startWithComAppAggregatorApiClient:] 
-[ComAppAggregatorSyncClientSyncSubscriptionRegistry addSubscriptionWithComAppAggregatorQueryQueryXML_Subscription:] 
-[ComAppAggregatorSyncClientSyncSubscriptionRegistry newSyncAndPostWithComAppAggregatorQueryQueryXML_QueryKey:] 
-[ComAppAggregatorSyncClientSyncSubscriptionRegistry writeUpdateWithComAppAggregatorQueryQueryXML_QueryKey:] 
-[ComAppAggregatorSyncClientSyncSubscriptionRegistry writeSubscriptions] 
-[JavaUtilTreeMap putWithId:withId:] TreeMap.m:371 
-[JavaUtilTreeMap createNodeWithId:withId:] TreeMap.m:634 
-[JavaUtilTreeMap_Node init] TreeMap.m:1463 
-[IOSObjectArray initWithLength:type:] IOSObjectArray.m:42 
calloc 
malloc_zone_calloc

问题1:最旧的堆栈框架位于顶部,最小的堆栈框架位于底部。因此thread_start调用_pthread_start,调用__NSThread__main__,调用-[NSThread main],依此类推。

问题2:名为-[NSThread main]的函数是实现main类的实例方法NSThread的函数。 Objective-C编译器可以生成具有名称(如-[NSThread main])的函数,这些函数无法在源代码中直接写出。

对于类方法,函数名称以+而不是-开头。因此,alloc上的类方法NSObject由名为+[NSObject alloc]的函数实现。

问题3:您发布的堆栈跟踪显示分配泄漏对象时的堆栈跟踪。该堆栈跟踪的任何部分都不一定“实际上是泄漏的那个”。

您需要了解对象泄露的含义。这意味着没有全局变量或局部变量(在堆栈上)指向泄漏的对象,或指向指向泄漏对象的对象,或指向指向泄漏对象的对象的对象因为没有指针链从全局或局部变量(我们在商业中说的“根指针”)开始并导致泄漏的对象,所以你的程序无法访问对象,即使它仍然被分配。

那为什么会泄露呢?因为在从指向对象的根指针的最后一个链之前没有释放它。它被泄露了,因为应该被调用的函数 - 释放函数 - 没有被调用。它应该在分配对象之后的某个时间被调用。由于泄漏工具仅在分配对象时向您显示堆栈跟踪,因此可能无法提供足够的信息来确定缺失的版本应该去哪里。

这让我们回到了乐器应用程序中的Leaks乐器。 Leaks仪器也无法显示您应该释放的确切位置,但它可以显示每次保留,释放和自动释放对象时的堆栈跟踪。这些额外的堆栈跟踪可以帮助您找出对象泄漏的原因。仪器还比泄漏命令行工具更好地格式化堆栈跟踪。如果您有泄露对象的网络,Instruments可以以图形方式向您显示该网络,这可以使您更容易理解您的应用程序泄漏对象的原因。

Apple发布了bunch of developer videos,其中一些会向您介绍乐器。我不记得究竟哪些视频或视频谈论泄漏检测,但我知道其中至少有一个。从WWDC 2012视频开始,然后继续前进。

修改

WWDC 2012视频“Session 409 - 学习乐器”讨论了在35分钟左右开始使用Leaks乐器。

WWDC 2011视频“会议310 - 仪器新功能”讨论了在39分钟左右开始使用泄漏仪器。

其他一些人也明确提到过。

答案 1 :(得分:0)

不确定您的问题是什么,但如果您正在尝试查找泄漏,此链接可以帮助您:Debugging Autorelease,不仅如果泄漏是由自动释放的对象引起的,它也很有用,因为它说如何记录malloc历史记录,启用僵尸并过滤malloc历史记录以跟踪对特定内存指针执行的所有alloc / release操作。