了解iOS上的仪器内存分配日志

我已经构build了一个即将完成的iOS应用程序,然而,由于“内存压力”,我最近经历了一段时间后崩溃。 所以我开始分析仪器中的内存分配情况,当然,这个应用程序确实使用了相当多的内存,而且在使用过程中似乎只会增加。

然而,相对较新的仪器内存分配我不能解码52%的分配,如下面的截图所示:

在这里输入图像说明

它显然与Core Animation有关,但是我确定的确难以确定,所以我认为那里有一些聪明的人可能知道答案。

面包屑:

我的应用程序使用自定义segues,当在视图控制器之间移动,其中有很多的animation正在发生。 这里是一个例子:

@interface AreaToKeyFiguresSegue : UIStoryboardSegue @end ... @implementation AreaToKeyFiguresSegue - (void)perform { [self sourceControllerOut]; } - (void)sourceControllerOut { AreaChooserViewController *sourceViewController = (AreaChooserViewController *) [self sourceViewController]; KeyFigureViewController *destinationController = (KeyFigureViewController *) [self destinationViewController]; double ratio = 22.0/sourceViewController.titleLabel.font.pointSize; sourceViewController.titleLabel.adjustsFontSizeToFitWidth = YES; [UIView animateWithDuration:TRANSITION_DURATION delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{ // Animate areaChooser sourceViewController.areaChooserScrollView.alpha = 0; sourceViewController.areaScrollViewVerticalSpaceConstraint.constant = -300; sourceViewController.backButtonVerticalConstraint.constant = 20; sourceViewController.backButton.transform = CGAffineTransformScale(sourceViewController.backButton.transform, ratio, ratio); sourceViewController.backButton.titleLabel.textColor = [UIColor redKombitColor]; sourceViewController.backArrowPlaceholderVerticalConstraint.constant = 14; sourceViewController.backArrowPlaceholder.alpha = 1; sourceViewController.areaLabelVerticalConstraint.constant = 50; sourceViewController.areaLabel.alpha = 1; [sourceViewController.view layoutIfNeeded]; } completion:^(BOOL finished) { [destinationController view]; // Make sure destionation view is initialized before animating it [sourceViewController.navigationController pushViewController:destinationController animated:NO]; // Push new viewController without animating it [self destinationControllerIn]; // Now animate destination controller }]; } - (void)destinationControllerIn { AreaChooserViewController *sourceViewController = (AreaChooserViewController *) [self sourceViewController]; KeyFigureViewController *destinationController = (KeyFigureViewController *) [self destinationViewController]; destinationController.keyFigureTableViewVerticalConstraint.constant = 600; destinationController.keyFigureTableView.alpha = 0.0; destinationController.allFavoritesSegmentedControl.alpha = 0.0; [destinationController.view layoutIfNeeded]; [sourceViewController.segueProgress setHidden:YES]; } @end 

而且每当一个视图控制器被popup时,我只是做相反的事情:

 - (IBAction)goBack:(id)sender { [UIView animateWithDuration:TRANSITION_DURATION delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{ [self.keyFigureTableView setAlpha:0]; self.keyFigureTableViewVerticalConstraint.constant = 700; [self.allFavoritesSegmentedControl setAlpha:0]; [self.view layoutIfNeeded]; } completion:^(BOOL finished) { [self.navigationController popViewControllerAnimated:NO]; // Pop viewController without animating it }]; } 

编辑:

大部分内存分配都是在推送视图控制器时发生的,即使之前已经显示过。 即将离开

A→B→C

B < – C

B – > C

其中“ – >”= push和“< – ”=popup,每个“ – >”分配更多的内存,“< – ”永远不会释放任何。

更多细节

根据仪器,我没有僵尸没有泄漏 。 静态分析也没有提供。 我的应用程序只是不断分配内存,直到最终崩溃。

大约70%的内存分配发生在下面的调用堆栈中,与我的代码(反向调用树)无关:

在这里输入图像说明

这是我如何debugging这些。

  1. 在仪器中,使用分配仪器并打开“logging参考计数”

在这里输入图像说明

  1. 运行您的应用程序到“稳定状态”,包括执行您认为正在泄漏几次的操作。

  2. 在乐器中,使用input/输出标记设置基线记忆水平。

  3. 执行您认为正在泄漏几次的操作。 (说7)

  4. 在仪器中,切换到显示所有分配的视图,并查找已分配的对象,但未释放与刚执行操作(也可能是7次)相同次数的对象。 您首先要尝试查找特定于您的程序的对象…因此,首选MyNetworkOperation实例,而不是像NSData这样的通用基础类。 点击您感兴趣的课程旁边的箭头单击分配的对象旁边的箭头

  5. select一个还没有被释放的对象,看看它的分配历史logging。 你将能够看到每个分配/保留/释放/ autorelease调用堆栈的调用堆栈。可能其中一个调用将看起来可疑。 所选对象的保留/释放历史

我想这些步骤更适用于非ARC环境。 在ARC之下,你可能正在寻找一个保留周期的东西。

一般来说,通过确保强引用只能朝一个方向运行,可以避免保留周期。例如,视图强烈引用其子视图,每个子视图只能使用弱引用来引用任何父视图。 或者你的视图控制器对你的视图有很强的参考。 您的视图只能对其视图控制器有一个弱引用。 另一种说法是在每个关系中决定哪一个对象“拥有”另一个对象。

工具是说,你的UIViews泄漏 (或不准确释放)。

每次推送都将创build一个新的destinationController控制器,并且目标控制器destinationController's视图将由CALayer支持,并且CALayer杀死内存。

为了certificate这一点,你可以为你的destinationController实现dealloc ,并在那里设置一个断点来查看它是否被调用。

如果调用dealloc,则可以对其他对象执行此操作以找出哪个对象。 (像destinationController.view

为什么泄漏?

1,您可能保留捕获destinationController周期。 debugging很痛苦,您可能需要检查所有相关的代码。

2,每个destinationController可能被一些长的活物保留下来。 (重复NSTimer不失效,Singleton,RootViewController,CADisplayLink …)

3,虚假caching。 你caching一些东西,并尝试重用它。 但是,caching逻辑有错误,这些对象永远不会被重用,新的对象不断被插入。

您的animation主要包含更改Alpha值或颜色。 为了减less自定义segue中的animation代码,我build议你将目标视图控制器(即方法destinationControllerIn )的animation代码移动到目标视图控制器的viewDidLoad:

首先检查是否(scheme诊断)你有僵尸打开。 僵尸意味着什么都不会被删除。 鉴于你的记忆力图表永远不会下降,这将是我的第一个检查。