0

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

MallocStackLogging=1 泄漏

泄漏:0x15d3cac0 大小=256 区域: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 方法1 | 类 2 方法 2 | Class3 Method3:这些代表什么?

2:物体描述前的正负号是什么意思?-[类方法] | +[类方法]

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

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

4

1 回答 1

5

使用 Leaks 工具(在 Instruments 应用程序中)在其扩展详细信息窗格中查看堆栈跟踪要容易得多。

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

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]您无法在源代码中逐字写出的名称(如 )的函数。

对于类方法,函数名以 a+而不是 a开头-。所以上面的类方法allocNSObject由一个名为 的函数实现的+[NSObject alloc]

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

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

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

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

Apple 发布了一堆开发者视频,其中一些向您介绍了 Instruments。我不记得究竟是哪些视频或哪些视频谈论泄漏检测,但我知道其中至少有一个。从 WWDC 2012 视频开始,然后继续工作。

编辑

WWDC 2012 视频“Session 409 - Learning Instruments”谈到了在大约 35 分钟后开始使用 Leaks 工具。

WWDC 2011 视频“Session 310 - What's New In Instruments”讨论了从大约 39 分钟开始使用 Leaks 仪器。

在其他一些人中也肯定提到过。

于 2012-11-15T07:15:15.610 回答