【问题标题】:Understanding Instruments memory allocation log on iOS了解 iOS 上的 Instruments 内存分配日志
【发布时间】:2013-12-26 15:24:30
【问题描述】:

我已经构建了一个几乎完成的 iOS 应用程序,但是,我最近经历了由于“内存压力”而导致它在一段时间后崩溃。所以我开始在 Instruments 中分析内存分配,并且确定,该应用确实使用了相当多的内存,而且它似乎只会在使用过程中增加。

但是,对于 Instruments 内存分配来说,我不太清楚 52% 的分配是在哪里进行的,如下面的屏幕截图所示:

这显然与核心动画有关,但我很难确定到底是什么,所以我认为那里的一些聪明人可能知道答案。

面包屑:

当在视图控制器之间移动时,我的应用使用自定义转场,其中会发生大量动画。这是一个例子:

@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

每当要弹出视图控制器时,我都会做相反的事情:

- (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
    }];
}

编辑:

大部分内存分配发生在推送视图控制器时,即使它之前已经显示过。 IE。从

A -> B -> C

B

B -> C

其中“->”=push,“”分配更多内存,“

更多详情

根据 Instruments,我没有僵尸并且没有泄漏。静态分析也没有给出任何结果。我的应用一直在分配内存,直到它最终崩溃。

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

【问题讨论】:

  • 使用“标记生成”按钮。在标尺上选择一个点,然后单击标记生成。然后选择右边的下一个点并再次单击标记生成,重复。 Instruments 将向您展示代际之间的差异——创建了哪些对象。
  • 我唯一能从中得到的是一堆十六进制地址,而调用者总是vm_allocate。
  • 您可以查看扩展详细信息面板以查看堆栈。您发布的图像不是很清晰,我几乎看不到那里有什么,但是如果我理解正确,Core Animation 会为视图的后备存储分配内存以在那里绘制一些东西。你有定义了drawRect的自定义视图吗?如果你注释掉 layoutIfNeeded 会发生什么?
  • 扩展细节基本上给出了与上述调用树相同的概述。如果我注释掉layoutIfNeeded,则基本上没有动画。
  • 那么你在你的布局代码中做了什么,可以post code sn-p吗?

标签: ios memory-management instruments


【解决方案1】:

这是我调试这些的方法。

  1. 在 Instruments 中,使用 Allocations 工具并打开“记录引用计数”

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

  2. 在 Instruments 中,使用输入/输出标记设置基线内存级别。

  3. 执行几次您认为会泄漏的操作。 (比如说 7)

  4. 在 Instruments 中,切换到显示所有分配的视图并查找已分配但未解除分配的对象,其次数与您刚刚执行的操作相同(同样可能是 7 次)。您首先要尝试找到特定于您的程序的对象...所以更喜欢MyNetworkOperation 实例而不是像NSData 这样的通用基础类。

  5. 选择尚未释放的对象之一并查看其分配历史记录。您将能够看到相关对象的每个 alloc/retain/release/autorelease 的调用堆栈。可能其中一个调用对您来说看起来很可疑。

我想这些步骤更适用于非 ARC 环境。在 ARC 下,您可能正在寻找保留周期的内容。

一般而言,您可以通过确保强引用仅在一个方向上来避免保留循环...例如,视图对其子视图具有强引用,并且每个子视图只能使用弱引用来引用任何父视图.或者您的视图控制器可能对您的视图有很强的引用。您的视图只能对其视图控制器进行弱引用。另一种说法是在每个关系中决定哪个对象“拥有”另一个对象。

【讨论】:

    【解决方案2】:

    Instruments 说您的 UIViews 正在泄漏(或者准确地说没有释放)。

    每次推送都会创建一个新的destinationController,destinationController's 视图将由 CALayer 支持,而 CALayer 会杀死内存。

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

    如果调用了 dealloc,那么您可以对其他对象执行此操作以找出哪个对象。 (喜欢destinationController.view)

    为什么要泄露?

    1,您可能有捕获destinationController 的保留周期。调试很麻烦,你可能需要检查所有相关的代码。

    2,每个destinationController 都可能被某个长生命的对象保留。 (不失效的重复NSTimer、Singleton、RootViewController、CADisplayLink ...)

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

    【讨论】:

    • 我已经在所有视图控制器和自定义 segues 中实现了 dealloc 方法的日志语句。推送后立即释放segues。然而,视图控制器不是。如果我去 A->B->C->B->A (我当然会在向后退时弹出)视图控制器 B 仅在长时间等待后才被释放。 C 永远不会被释放。
    • 这种内存泄漏是最难调试的。我可能采取的解决方案是注释掉绝对安全的代码/文件,直到我找到导致泄漏的行。有时,即使是 iOS 也可能存在导致视图控制器从未发布的错误。
    【解决方案3】:

    您的动画主要包含不断变化的 alpha 值或颜色。为了减少自定义segue中的动画代码,我建议您将目标视图控制器的动画代码(即方法destinationControllerIn)移动到目标视图控制器的viewDidLoad:。

    【讨论】:

      【解决方案4】:

      首先检查(方案诊断)您是否打开了僵尸。僵尸意味着什么都不会被删除。鉴于您的记忆图从不下降,这将是我的第一次检查。

      【讨论】:

      • 我没有收到任何“僵尸消息”对话框,如果这是我应该得到的?
      • 只有在您实际向已删除对象发送消息时才会收到这些错误。不,问题是没有任何东西被删除,导致内存不断增长。僵尸通过不丢弃任何东西并将对象变成特殊的 NSZombie 类来工作。
      • 是的,但除非我向其发送 obj-c 消息,否则我从不知道僵尸,显然我没有。
      • 投了反对票,因为这是僵尸的错误含义。僵尸是被过度释放的东西。向僵尸发送消息会导致访问错误。您指的是内存泄漏,其中某些内容永远不会完全释放,从而导致内存压力。
      • 谢谢@PatrickGoley,我也很困惑。但是,根据 Instruments,我也没有内存泄漏。
      猜你喜欢
      • 2010-11-06
      • 2019-07-08
      • 1970-01-01
      • 2021-09-25
      • 1970-01-01
      • 2011-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多