我已经构建了一个几乎已经完成的iOS应用程序,但是,我最近经历过由于“内存压力”导致它崩溃的情况。所以我开始分析仪器中的内存分配,当然,应用程序确实使用了相当多的内存,而且在使用过程中似乎只会增加。
然而,相对较新的仪器内存分配,我无法破译52%的分配,如下面的屏幕截图所示:
它显然与Core Animation有关,但究竟是什么对我来说难以确定,所以我认为一些聪明的头脑可能知道答案。
我的应用程序使用自定义segue,在视图控制器之间移动时,正在进行大量动画制作。这是一个例子:
@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
}];
}
大多数内存分配在推送视图控制器时发生,即使它之前已经显示过。即从
开始A - > B - > ç
B < - C
B - &gt; ç
其中“ - &gt;” = push和“&lt; - ”= pop,每个“ - &gt;”分配更多内存,“&lt; - ”永远不会释放任何内存。
根据乐器,我有没有僵尸和没有泄漏。静态分析也没有给出什么。我的应用程序只是继续分配内存,直到它最终崩溃。
大约70%的内存分配发生在以下调用堆栈中,这与我的代码(反向调用树)无关:
答案 0 :(得分:6)
以下是我调试这些内容的方法。
将您的应用运行至“稳定状态”,包括执行您认为会泄漏几次的操作。
在仪器中,使用输入/输出标记设置基线记忆水平。
执行您认为泄漏几次的操作。 (比如说7)
在Instruments中,切换到显示所有分配的视图,并查找已分配但未解除分配的对象与您刚刚执行的操作相同的次数(也可能是7次)。您首先要尝试查找特定于您的程序的对象...所以更喜欢MyNetworkOperation
个实例而不是像NSData
这样的通用基础类。
选择一个尚未解除分配的对象,并查看其分配历史记录。您将能够看到相关对象的每个alloc / retain / release / autorelease的调用堆栈。可能其中一个调用看起来很可疑。
我认为这些步骤在非ARC环境中的应用更多。在ARC下你可能正在寻找一个保留周期的东西。
通常,您可以通过确保强引用仅朝一个方向来避免保留周期...例如,视图具有对其子视图的强引用,并且每个子视图必须仅使用弱引用来引用任何父视图。或者您的视图控制器可能会强烈引用您的视图。您的视图必须仅对其视图控制器具有弱引用。另一种说法是在每个关系中决定哪个对象“拥有”另一个对象。
答案 1 :(得分:2)
乐器说你的 UIViews正在泄漏(或者说没有准确地解除分配)。
每次推送都会创建一个新的destinationController
,destinationController's
视图将由CALayer支持,CALayer会杀死内存。
为了证明这一点,您可以为dealloc
实施destinationController
并在那里设置一个断点,看看它是否被调用。
如果调用dealloc,则可以对其他对象执行此操作以找出哪一个。 (如destinationController.view
)
为什么要泄漏?
1,您可能有保留捕获destinationController
的周期。调试很麻烦,您可能需要检查所有相关的代码。
2,每个destinationController
可能会被一些长生命物体保留。 (重复的NSTimer没有失效,Singleton,RootViewController,CADisplayLink ...)
答案 2 :(得分:0)
您的动画主要包含更改的Alpha值或颜色。为了减少自定义segue中的动画代码,我建议您将目标视图控制器的动画代码(即方法destinationControllerIn
)移动到目标视图控制器的viewDidLoad:
。
答案 3 :(得分:-2)
首先检查(方案诊断)是否已打开僵尸。僵尸意味着什么都没有被删除。鉴于你的记忆图表永远不会下降,这将是我第一次检查。