当我用以下命令调用leaks时,我有以下malloc堆栈跟踪:
MallocStackLogging=1泄漏
泄漏:0x15d3ac0大小=256区域:默认MallocZone_0x7b0000
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|Class2方法2|Class3方法3:这些是什么意思?
2:物体描述前的正负号是什么意思?-[类方法]|+[类方法]
3:以下哪一个是真正泄漏的?我无法准确确定堆栈跟踪的哪个对象/部分正在泄漏。
任何文件链接都会很棒!
使用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]
的函数是实现NSThread
类的实例方法main
的函数。Objective-C编译器可以生成具有名称的函数(如-[NSThread main]
),而这些名称在源代码中无法直接写出。
对于类方法,函数名称以+
开头,而不是以-
开头。因此,NSObject
上的类方法alloc
是由一个名为+[NSObject alloc]
的函数实现的。
问题3:您发布的堆栈跟踪显示了分配泄漏对象时的堆栈跟踪。堆栈跟踪的任何部分都不一定是"实际泄漏的部分"。
你需要了解对象被泄露意味着什么。这意味着没有全局变量或局部变量(在堆栈上)指向泄漏的对象,或指向指向泄漏对象的对象,或者指向指向指向泄漏目标的对象的对象,等等。由于没有从全局或局部变量(我们在biz中所说的"根指针")开始并导致泄漏对象的指针链,因此即使对象仍然被分配,您的程序也无法访问该对象。
那么,为什么它会被泄露呢?因为在从根指针到对象的最后一个链断开之前,它并没有被释放。它之所以被泄露,是因为本应调用的函数——发布函数——没有被调用。它应该在分配对象后的某个时间被调用。由于leaks工具只在分配对象时向您显示堆栈跟踪,因此它可能无法为您提供足够的信息来确定丢失的版本应该放在哪里。
这让我们回到仪器应用程序中的Leaks仪器。Leaks仪器也不能向您显示应该释放的确切位置,但它可以向您显示每次保留、释放和自动释放对象时的堆栈轨迹。这些额外的堆栈跟踪可以帮助您找出对象泄漏的原因。与leaks命令行工具相比,Instruments还可以更好地格式化堆栈跟踪。如果你有一个泄露对象的网络,Instruments可以以图形方式向你显示该网络,这可能会让你更容易理解你的应用程序泄露对象的原因。
苹果公司发布了一系列开发者视频,其中一些视频向你介绍了仪器。我不记得具体是哪一个或哪些视频谈到了泄漏检测,但我知道其中至少有一个谈到了。从WWDC 2012视频开始,一路回归。
编辑
WWDC 2012视频"会话409-学习仪器"谈到使用Leaks仪器大约35分钟开始。
WWDC 2011视频"Session 310-What’s New In Instruments"谈到了使用Leaks仪器,大约从39分钟开始。
在其他一些文章中肯定也提到了这一点。