【问题标题】:Expensive renderInContext memory usage on main thread主线程上昂贵的 renderInContext 内存使用
【发布时间】:2017-12-08 10:43:06
【问题描述】:

我正在使用在主线程上执行的以下代码来截取 屏幕外(不是 self.view 的子视图) 视图的屏幕截图,然后显示在 UIImageView 中.就功能而言,一切正常,但是由于此代码在扩展上运行,因此内存限制要严格得多(我读过大约 30 MB 是上限?),

UIGraphicsBeginImageContextWithOptions(CGSizeMake(self.screenshotView.frame.size.width, self.screenshotView.frame.size.height-2), YES, 0.0f);
CGContextRef context = UIGraphicsGetCurrentContext();
[self.screenshotView.layer renderInContext:context];
_generatedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

self.previewImageView.image = _generatedImage;

每当按下UIButton 时,都会使用performSelectorOnMainThread 调用此代码所在的方法。还提供了一个UIAlertController 来处理UI 的冻结,但是如果连续按下按钮(在关闭UIAlertController 之后),前几次内存使用量将保持在基线附近(~15 MB),但随后飙升至约 30 MB 并停留在那里,直到几秒钟后再次调用该方法,然后当它完成渲染时,它会回落到约 15 MB。

我不确定是什么导致了这种行为,为什么内存使用量不会一直保持在 ~15 MB 左右,我不确定当连续调用该方法时它出现峰值的原因是什么.听起来更像是一件事有时同时发生?我怎样才能确保不会发生这种情况,并且只有在可以安全地再次渲染而不会增加内存使用时才关闭 UIAlertController

【问题讨论】:

    标签: ios objective-c memory rendering uigraphicscontext


    【解决方案1】:

    内存峰值不是由于 renderInContext: 调用,尽管包括指向它的仪器在内的所有内容,但它是由于捕获的 UIViewsubviews。就我而言,这是一个错误的约束,导致 UITextView 将其 height 设置为 2000

    对于遇到此类问题但无法解决的任何人,请从renderInContext: 继续并查看您的子视图以确保它们正确。

    【讨论】:

      【解决方案2】:

      1.您能否详细说明您为什么要在主线程上捕获屏幕截图?异步运行:

      dispatch_async(dispatch_get_global_queue(0, 0), ^{
      });
      

      这可能会解决挂起问题并尝试在autoreleasepool 中执行这些代码行,这将有助于减少内存占用。

      2.您尝试过drawViewHierarchyInRect: afterScreenUpdates:吗?它更快、效率更高,有助于解决您的内存问题。

      该方法渲染到上下文,然后您可以调用:

      CGImageRef image = CGBitmapContextCreateImage(UIGraphicsGetCurrentContext());
      

      但它应该在autoreleasepool 中执行。如果不是,那么内存会不断增加。

      编辑

      3.如果您可以使用同步捕获方法防止创建多个上下文。它可能有助于增加内存:

      dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
      dispatch_queue_t renderQueue = dispatch_queue_create("com.throttling.queue", NULL);
      
      - (void) captureScreen {
          if (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW) == 0) {
              dispatch_async(renderQueue, ^{
                  // capture
                  dispatch_semaphore_signal(semaphore);
              });
          }
      }
      

      【讨论】:

      • drawViewHierarchyInRect: 如果我要截屏的视图不是子视图,则无法正常工作,对吗?它不是子视图,如果我的测试没记错的话,它会呈现黑色图像。
      • 还尝试异步运行它,同样的内存峰值,现在尝试与自动释放池异步。
      • 即使自动释放池异步运行也不走运。
      • 是的,您应该有视图参考才能使用 drawViewHierarchyInRect。您是否尝试过在 controller.view 上调用它?它将在顶部捕获您当前的视图。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-26
      • 1970-01-01
      • 1970-01-01
      • 2012-06-13
      • 2019-04-08
      • 1970-01-01
      相关资源
      最近更新 更多