长时间使用后应用程序和操作系统滞后

Posted

技术标签:

【中文标题】长时间使用后应用程序和操作系统滞后【英文标题】:App and OS lagging after long usage 【发布时间】:2012-11-21 20:02:14 【问题描述】:

我有一个应用程序在使用大约 30-35 分钟后会降低整个操作系统的速度。滞后是渐进的,我可以看到它随着时间的推移而增加,因为我一遍又一遍地重复相同的操作。这是一个音乐应用程序,在播放大约 15-20 首曲目后,延迟令人难以忍受。

在 UIScrollView 中滚动项目时,帧速率下降到 10 以下。很多帧被跳过并且 UI 几乎锁定。如果我在应用程序后台运行,我会在 SpringBoard 中的操作系统中看到这种滞后,基本上无处不在。在 SpringBoard 中滚动应用程序图标变得不连贯。解锁的幻灯片变得不稳定等。

我将如何解决这个问题?可能是什么原因。由于代码库相当复杂,我无法削减代码以创建最小的可重现示例。我需要帮助来了解可能导致操作系统几乎锁定的原因。这不是死锁,因为 UI 仍然会响应,只是需要很长时间。

哪些分析工具可以帮助找出导致此问题的原因?我怀疑这可能是因为内存泄漏,但令人惊讶的是操作系统没有向应用程序发送内存警告,所以我也不完全确定。

非常感谢任何帮助。

【问题讨论】:

【参考方案1】:

问题在于动画的堆积。活动监视器在调试此问题时最有用。 Springboard 的 CPU 使用率不断上升,直到达到 100%。所以时间显然没有花在我的应用程序上,而是在 Springboard 中的渲染服务器上。

我创建了两个具有大量重复次数的动画,让它们永远运行。然后我将每个动画添加到一个单独的层。为了创建动画,我使用了惰性检查,并使用给定键向图层询问任何现有动画。如果图层什么也没返回,我就创建了动画。问题是图层总是什么都不返回,所以我一直在创建这些永远重复的动画。

这是有问题的代码。

// This call always returned nil.
CABasicAnimation *innerRotationAnimation = (CABasicAnimation *)[self.spinnerViewInner.layer animationForKey:@"rotationAnimation"];

// So I kept on creating animations and piling them up.
if (innerRotationAnimation == nil)

    CATransform3D innerRotationTransform = CATransform3DMakeRotation(0.25f * M_PI * -1, 0, 0, 1.0);
    innerRotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
    innerRotationAnimation.toValue = [NSValue valueWithCATransform3D:innerRotationTransform];
    innerRotationAnimation.duration = 0.25f;
    innerRotationAnimation.cumulative = YES;
    innerRotationAnimation.repeatCount = HUGE_VALF;
    [self.spinnerViewInner.layer addAnimation:innerRotationAnimation forKey:@"rotationAnimation"];

为了解决这个问题,我开始删除现有的动画。我可以在两个点上做到这一点,要么在animationDidStop:finished: 回调中,要么在我的setAnimating: 方法中,并且都运行良好。这是setAnimating: 方法的变化。

- (void)setAnimating:(BOOL)animating

    if (animating == NO) 
        // Remove all existing animations now.
        [self.layer removeAllAnimations];
    
    else 
        CABasicAnimation *animation = // Create animation;
        [self.layer addAnimation:animation forKey:@"rotationAnimation"];
    

如果有人感兴趣,这里是原始 BROKEN 代码。

- (void)setAnimating:(BOOL)animating

    if (self.isAnimating == animating)
    
        return;
    

    _animating = animating;

    if (self.isAnimating == YES)
    
        CABasicAnimation *innerRotationAnimation = (CABasicAnimation *)[self.spinnerViewInner.layer animationForKey:@"rotationAnimation"];
        CABasicAnimation *outerRotationAnimation = (CABasicAnimation *)[self.spinnerViewOuter.layer animationForKey:@"rotationAnimation"];

        if (innerRotationAnimation == nil)
        
            CATransform3D innerRotationTransform = CATransform3DMakeRotation(0.25f * M_PI * -1, 0, 0, 1.0);
            innerRotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
            innerRotationAnimation.toValue = [NSValue valueWithCATransform3D:innerRotationTransform];
            innerRotationAnimation.duration = 0.25f;
            innerRotationAnimation.cumulative = YES;
            innerRotationAnimation.repeatCount = HUGE_VALF;
            [self.spinnerViewInner.layer addAnimation:innerRotationAnimation forKey:@"rotationAnimation"];
        
        if (outerRotationAnimation == nil)
        
            CATransform3D outerRotationTransform = CATransform3DMakeRotation(0.25f * M_PI * -1, 0, 0, -1.0);
            outerRotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform"];
            outerRotationAnimation.toValue = [NSValue valueWithCATransform3D:outerRotationTransform];
            outerRotationAnimation.duration = 0.25f;
            outerRotationAnimation.cumulative = YES;
            outerRotationAnimation.repeatCount = HUGE_VALF;
            [self.spinnerViewOuter.layer addAnimation:outerRotationAnimation forKey:@"rotationAnimation"];
        
    


- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag

    self.spinnerViewInner.layer.opacity = (self.isAnimating ? 1.0 : 0.0);
    self.spinnerViewOuter.layer.opacity = (self.isAnimating ? 1.0 : 0.0);

不过,有一件事我仍然很好奇。由于给定键只能有一个活动动画,当我尝试添加具有相同键的新动画时,Core Animation 不应该删除我现有的动画吗?为什么animationForKey: 会返回nil

【讨论】:

【参考方案2】:

使用仪器找出发生了什么。线程的失控产卵?内存泄漏?见https://developer.apple.com/library/ios/#documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/Introduction/Introduction.html

【讨论】:

我正在使用各种工具,包括 Time Profiler、Core Animation、Open GL ES,但它们并未指出任何问题区域。设备利用率保持在 10-20% 左右,所以我没有给 GPU 施加压力。 Time Profiler 没有显示任何明显的东西,比如每次迭代都会增加工作量,所以这也无济于事。你知道我可以使用哪些其他工具来进行更多调试吗? 分配、泄漏和活动监视器。 感谢您的提示。 Activity Monitor 是一个很好的起点,它引导我朝着正确的方向前进。

以上是关于长时间使用后应用程序和操作系统滞后的主要内容,如果未能解决你的问题,请参考以下文章

Android 长时间待机后系统概率性无声

Android 长时间待机后系统概率性无声

Android 长时间待机后系统概率性无声

Mysql - 用多个前行(不仅仅是一个)模拟滞后

长时间运行的 Azure WebJob 失败 - 客户端无法在指定的超时时间内完成操作

C# WPF - 按钮单击的长时间操作