【问题标题】:Why updating CALayer causes increase of CPU usage (by other processes) by 60-70%?为什么更新 CALayer 会导致 CPU 使用率(其他进程)增加 60-70%?
【发布时间】:2019-07-02 14:01:56
【问题描述】:

当界面由许多 CALayers 呈现时,我正在使用 IOS 应用程序。一旦我注意到 CPU 在图形更新期间被其他进程(实际上不是应用程序)加载。我开始禁用界面部件的更新,直到只有一个 CALayer 被更新(50-60 Hz),但所有其他层(数百个)都是静态的也显示出来了。因此,仅更新这一层会消耗 60-70% 的 CPU 其他进程的负载。当禁用此唯一层的更新时,CPU 不会加载。

谁能说说这是怎么回事?

[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];

// update layer which is sublayer of self.view.layer
self.headingCircularScaleLayer.transform = CATransform3DMakeRotation(DegToRad(-newHeadingAngle_deg), 0, 0, 1);

[self.view.layer setNeedsLayout];

[CATransaction commit];

这里 headingCircularScaleLayer 是 CALayer,其内容设置为某个 Image

NOTE_1:(通过添加许多层并更新它们来测试 CPU 负载)

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
}

-(void) viewDidAppear:(BOOL)animated {

    [self createAndSetupLayers];

    CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(updateLayers)];
    [displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];

    self.startTime = [[NSDate date] timeIntervalSince1970];
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}


-(void) createAndSetupLayers {

    NSMutableArray<CALayer*>* newLayersArray = [[NSMutableArray alloc] init];

    long numOfRows = 28;
    long numOfCols = 21;
    long numOfLayers = numOfRows * numOfCols;

    CGFloat cellWidth = self.view.bounds.size.width / numOfCols;
    CGFloat cellHeight = self.view.bounds.size.height / numOfRows;

    CGFloat layerWidth = cellWidth * 0.9;
    CGFloat layerHeight = cellHeight * 0.9;

    long currRow = 0;
    long currCol = 0;

    for (long i = 0; i < numOfLayers; i++)
    {
        currRow = i / numOfCols;
        currCol = i % numOfCols;

        CALayer* newLayer = [[CALayer alloc] init];

        newLayer.bounds = CGRectMake(0.0, 0.0, layerWidth, layerHeight);
        newLayer.anchorPoint = CGPointMake(0.5, 0.5);
        newLayer.position = CGPointMake((currCol + 0.5) * cellWidth, (currRow + 0.5) * cellHeight);
        newLayer.backgroundColor = [UIColor greenColor].CGColor;
        //newLayer.opacity = 0.5;

        //NSDictionary *newActions = @{ @"transform": [NSNull null] };
        //newLayer.actions = newActions;
        newLayer.actions = @{ @"contents": [NSNull null], @"position": [NSNull null],
                           @"frame": [NSNull null], @"opacity": [NSNull null],
                           @"bounds": [NSNull null], @"affineTransform": [NSNull null],
                           @"sublayerTransform": [NSNull null], @"transform": [NSNull null],
                           @"zPosition": [NSNull null], @"anchorPoint": [NSNull null],
                           @"cornerRadius": [NSNull null], @"sublayers": [NSNull null],
                           @"onLayout": [NSNull null], };


        CALayer* newColorLayer = [[CALayer alloc] init];
        newColorLayer.bounds = CGRectMake(0.0, 0.0, layerWidth, layerHeight);
        newColorLayer.anchorPoint = CGPointMake(0.5, 0.5);
        newColorLayer.position = CGPointMake(0.5 * layerWidth, 0.5 * layerHeight);
        newColorLayer.opacity = 0.5;
        newColorLayer.opaque = YES;
        newColorLayer.backgroundColor = [UIColor redColor].CGColor;

        //[newLayer addSublayer:newColorLayer];
        [self.view.layer addSublayer:newLayer];
        [newLayersArray addObject:newLayer];
    }

    self.layersArray = newLayersArray;
}

-(void) updateLayers {
    double currTime = [[NSDate date] timeIntervalSince1970] - self.startTime;

    double currLayerAngle = 0.5 * currTime;

    NSLog(@"%.2f  %.2f", currTime, currLayerAngle);

    //[CATransaction begin];
    //[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
    //[CATransaction setAnimationDuration:0.0];

    for (CALayer *currLayer in self.layersArray)
    {
        currLayer.transform = CATransform3DMakeRotation(currLayerAngle, 0, 0, 1);
    }

    //[CATransaction commit];
}

@end

【问题讨论】:

  • 你能分享一些代码吗?您使用 CALayer 做什么以及如何做的?
  • 你是在真机还是模拟器上测试?最好在真机上测试性能
  • 添加代码到描述
  • 我在真机上测试。在活动监视器中,它显示一些 backboardd 在更新期间占用了大量 CPU。
  • 您必须将持续时间设置为 0.0s。所有动画属性都没有动画。否则默认时间为 0.25,这对性能问题不利。如果您只使用 disableActions,在这种情况下,transform 持续时间为 0.0,但其他,如不透明度、隐藏等,持续时间仍为 0.25 秒。换句话说,CATransaction 不应该立即完成。

标签: ios performance core-animation calayer cpu-usage


【解决方案1】:

如上面cmets所说,设置kCATransactionDisableActions只会影响当前事务。您可能在其他地方有启动隐式动画的代码。尝试将图层操作显式设置为空。您只需在创建图层时执行此操作一次。在这种情况下,您不需要进行显式事务。

layer.actions = @{ @"contents": [NSNull null], @"position": [NSNull null],
                   @"frame": [NSNull null], @"opacity": [NSNull null],
                   @"bounds": [NSNull null], @"affineTransform": [NSNull null],
                   @"sublayerTransform": [NSNull null], @"transform": [NSNull null],
                   @"zPosition": [NSNull null], @"anchorPoint": [NSNull null],
                   @"cornerRadius": [NSNull null], @"sublayers": [NSNull null],
                   @"onLayout": [NSNull null], };

【讨论】:

  • 我尝试了你的建议,但 CPU 仍然加载。我在问题描述中添加了我的测试代码作为 NOTE_1。请看一下..
  • 我不明白为什么CPU参与层更新??在 NOTE_1 的测试代码中,我尝试更改层数:层数越多,CPU 负载越多。似乎每次更新都会将层从 GPU 内存卸载到 RAM 以便在 CPU 中处理。如果不是,那又是什么……?此外,在彩色层后面添加空层也会导致 CPU 浪费。为什么如果它是空的并且可以被视为容器?谜团..
猜你喜欢
  • 2020-01-27
  • 1970-01-01
  • 1970-01-01
  • 2012-10-09
  • 1970-01-01
  • 1970-01-01
  • 2011-02-20
  • 1970-01-01
  • 2021-02-18
相关资源
最近更新 更多