了解iOS上的仪器内存分配日志 [英] Understanding Instruments memory allocation log on iOS

查看:142
本文介绍了了解iOS上的仪器内存分配日志的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经构建了一个几乎已经完成的iOS应用程序,但是,我最近经历过它由于内存压力而崩溃。所以我开始分析仪器中的内存分配,当然,应用程序确实使用了相当多的内存,而且在使用过程中似乎只会增加。

I have built an iOS app that is almost done, however, I have recently experienced that it crashes after while due to "Memory pressure". So I started profiling the memory allocations in Instruments and sure, the app does use quite a lot of memory and it only seems to increase during usage.

但是,相对较新的仪器内存分配我无法破译52%的分配,如下面的屏幕截图所示:

However, relatively new to Instruments memory allocation I am not quite able to decipher where 52 % of the allocations are made, as seen in the screenshot below:

它显然与Core Animation有关,但到底是什么我很难确定,所以我认为一些聪明的头脑可能知道答案。

It has obviously got something to do with Core Animation, but what exactly is hard for me to determine, so I thought that some clever minds out there might know the answer to that.

我的应用程序使用自定义segue,在视图控制器之间移动时,正在进行大量动画制作。下面是一个例子:

My app uses custom segues, when moving between view controllers, where a lot of animation is taking place. Here is an example:

@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

每当视图控制器是要弹出,我只是做相反的事情:

And whenever a view controller is to be popped, I simply do the reverse thing:

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



编辑:



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

Most of the memory allocation takes place when pushing a view controller, even if it has already been displayed before. I.e. going from

A - > B - > C

A -> B -> C

B< - C

B <- C

B - > C

其中 - >= push和< - = pop,每个 - >分配更多内存和< - 永远不会释放任何内容。

where "->" = push and "<-" = pop, each "->" allocates more memory and "<-" never releases any.

我有否根据乐器,僵尸无泄漏。静态分析也没有给出什么。我的应用程序只是保持分配内存,直到它最终崩溃。

I have no zombies and no leaks according to Instruments. Static analysis also gives nothing. My app just keeps allocating memory until it finally crashes.

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

Around 70 % of my memory allocation happens in the following call stack, which has nothing to do with my code (inverted call tree):

推荐答案

以下是我调试这些内容的方法。

Here's how I debug these.


  1. 在仪器中,使用分配工具并启用记录参考计数


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

  1. Run your app to a "steady state", including performing the operation you think is leaking a few times.

在Instruments中,使用以下方法设置基准内存级别输入/输出标记。

In Instruments, set your baseline memory level using the in/out markers.

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

Perform the operation you think is leaking a few times. (say 7)

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

In Instruments, switch to the view that shows all allocations and look for objects that have been allocated yet not deallocated the same number of times as the operation you just performed (again maybe 7 times). You'll first want to try to find an object specific to your program... So prefer MyNetworkOperation instances instead of generic foundation classes like NSData.

选择一个尚未取消分配的对象并查看这是分配历史。您将能够看到相关对象的每个alloc / retain / release / autorelease的调用堆栈。可能其中一个调用看起来很可疑。

Select one of the objects that hasn't been deallocated and look at it's allocation history. You'll be able to see the call stack for every alloc/retain/release/autorelease for the object in question.. Probably one of the calls will look suspicious to you.

我认为这些步骤在非ARC环境中应用得更多。在ARC下你可能正在寻找一个保留周期的东西。

I suppose these steps apply more in a non-ARC environment. Under ARC you might be looking for something that's a retain cycle.

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

In general you can avoid retain cycles by making sure your strong references only go in one direction... For example, a view has strong references to it's subviews and each subview must only ever use weak references to refer to any parent view. Or perhaps your view controller has a strong reference to your view. Your view must only have a weak reference to its view controller. Another way to say this is to decide in each relationship which object "owns" the other.

这篇关于了解iOS上的仪器内存分配日志的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆