主线程上昂贵的 renderInContext 内存使用
Expensive renderInContext memory usage on main thread
我正在使用在主线程上执行的后续代码来截取 关闭屏幕的屏幕截图(不是 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
。
1.Could 您详细说明了为什么要在主线程上捕获屏幕截图? 运行 它异步于:
dispatch_async(dispatch_get_global_queue(0, 0), ^{
});
这可能会解决挂起问题并尝试在 autoreleasepool
中执行这些代码行,这将有助于减少内存占用。
2.Have 您尝试过 drawViewHierarchyInRect: afterScreenUpdates:
它更快并且可以更有效地帮助您解决内存问题。
该方法呈现给上下文,然后您可以调用:
CGImageRef image = CGBitmapContextCreateImage(UIGraphicsGetCurrentContext());
但它应该在 autoreleasepool
内执行。如果不是,那么内存会继续增加。
编辑
3.If 您可以通过同步捕获来防止创建多个上下文 method.It 可能有助于增加内存:
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);
});
}
}
内存峰值不是由于 renderInContext:
调用引起的,尽管包括仪器在内的所有东西都指向它,而是由于捕获的 UIView
的 subviews
。在我的例子中,这是一个错误的约束导致 UITextView
将其 height
设置为 2000
。
对于遇到此类问题且无法解决的人,请从 renderInContext:
继续并查看您的子视图以确保它们是正确的。
我正在使用在主线程上执行的后续代码来截取 关闭屏幕的屏幕截图(不是 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
。
1.Could 您详细说明了为什么要在主线程上捕获屏幕截图? 运行 它异步于:
dispatch_async(dispatch_get_global_queue(0, 0), ^{
});
这可能会解决挂起问题并尝试在 autoreleasepool
中执行这些代码行,这将有助于减少内存占用。
2.Have 您尝试过 drawViewHierarchyInRect: afterScreenUpdates:
它更快并且可以更有效地帮助您解决内存问题。
该方法呈现给上下文,然后您可以调用:
CGImageRef image = CGBitmapContextCreateImage(UIGraphicsGetCurrentContext());
但它应该在 autoreleasepool
内执行。如果不是,那么内存会继续增加。
编辑
3.If 您可以通过同步捕获来防止创建多个上下文 method.It 可能有助于增加内存:
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);
});
}
}
内存峰值不是由于 renderInContext:
调用引起的,尽管包括仪器在内的所有东西都指向它,而是由于捕获的 UIView
的 subviews
。在我的例子中,这是一个错误的约束导致 UITextView
将其 height
设置为 2000
。
对于遇到此类问题且无法解决的人,请从 renderInContext:
继续并查看您的子视图以确保它们是正确的。