imageWithCGImage:GCD内存问题
当我只在主线程执行以下操作时, iref
立即获得autoreleased:
-(void)loadImage:(ALAsset*)asset{ @autoreleasepool { ALAssetRepresentation* rep = [asset defaultRepresentation]; CGImageRef iref = [rep fullScreenImage]; UIImage* image = [UIImage imageWithCGImage:iref scale:[rep scale] orientation:UIImageOrientationUp]; [self.imageView setImage:image]; } }
但是当我执行imageWithCGImage时:在后台线程上使用GCD iref
不会像第一个例子那样立即被释放。 只有一分钟后:
-(void)loadImage:(ALAsset*)asset{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) { @autoreleasepool { ALAssetRepresentation* rep = [asset defaultRepresentation]; CGImageRef iref = [rep fullScreenImage]; UIImage* image = [UIImage imageWithCGImage:iref scale:[rep scale] orientation:UIImageOrientationUp]; dispatch_async(dispatch_get_main_queue(), ^(void) { [self.imageView setImage:image]; }); } }); }
我怎样才能让CGImageRef
对象立即被释放?
先前研究:
- 当我用它logging时,泄漏仪器不显示任何泄漏。
- 分配工具显示一个
CGImageRef
对象被分配,并且在应该被释放之后仍然活着一分钟左右。 - 如果我尝试使用
CGImageRelease
手动释放CGImageRef
对象,CGImageRelease
在图像尝试获取自动释放后,我会在一分钟后得到一个BAD_EXECexception。 - 使用
CGImageRetain
保留iref
,然后使用CGImageRelease
释放它不起作用。 - 类似的问题在stackoverflow没有帮助: 图像加载与gcd , 在创build图像收到内存警告, 从alaseet结果获取fullscreenimage时内存泄漏 ,
首先,没有一个“自动释放”CF对象的概念。 在处理免费的桥接类时,可能会遇到这种情况,但您可以看到,有一个CFRetain
和一个CFRelease
但没有CFAutorelease
。 所以我认为你是在误解iref
的所有权。 让我们来追踪这个代码的所有权:
-(void)loadImage:(ALAsset*)asset{
asset
被传递到这个方法。 其保留数至less为1。
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
封锁收回asset
。
@autoreleasepool { ALAssetRepresentation* rep = [asset defaultRepresentation];
这将通过命名约定返回您不拥有的对象。 它可能是autoreleased,它可能是一个单身/全球等,但你不拥有它,不应该通过保留它拥有它。
CGImageRef iref = [rep fullScreenImage];
由于没有“autoreleased”CF对象的概念,我们将假定rep
向您返回一个指向由rep
拥有的CGImageRef
的内部指针。 你也不拥有这个,不应该保留它。 相关的,你不能控制什么时候会消失。 一个合理的猜测是,它会活到只要rep
和一个合理的猜测是rep
将生活只要asset
所以你可能应该假设iref
将至less与asset
一样长。
UIImage* image = [UIImage imageWithCGImage:iref scale:[rep scale] orientation:UIImageOrientationUp];
如果UIImage需要使用CGImageRef,则需要保留或复制以确保它保持活动状态。 (可能是后者)UIImage本身是通过命名约定自动释放的。
dispatch_async(dispatch_get_main_queue(), ^(void) {
这个内部封锁将要保留image
(和self
)。 该块将被libdispatch复制,延长这些保留的生命周期,直到块被执行并被释放。
[self.imageView setImage:image];
如果需要,图像视图将对图像进行保留(或复制),以便完成其工作。
});
内部块完成执行。 在将来的某个时候,libdispatch将会释放它,这会通过self
和image
传递释放被闭包占用的保留。
}
你的autorelease池在这里popup。 任何隐式保留/自动释放的东西现在应该被释放。
});
外部块完成执行。 在将来的某个时候,libdispatch会释放它,这将会过度释放由asset
上的块closures所带来的保留。
}
最终,这个方法不能控制iref
中的CGImageRef的生命周期,因为它永远不拥有它的所有权。 这里的含义是,CGImageRef是由asset
过渡性拥有的,所以它至less会和asset
一样长。 由于在外部块中使用asset
(即由外部块的封闭保留),并且由于libdispatch没有承诺何时完成块将被释放,所以实际上不能保证iref
将会早于libdispatch得到它。
如果你想去手动保留/释放,并尽可能的明确,你可以这样做:
-(void)loadImage:(ALAsset*)asset{ __block ALAsset* weakAsset = [asset retain]; // asset +1 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) { @autoreleasepool { ALAssetRepresentation* rep = [weakAsset defaultRepresentation]; CGImageRef iref = [rep fullScreenImage]; UIImage* image = [[UIImage alloc] imageWithCGImage:iref scale:[rep scale] orientation:UIImageOrientationUp]; __block UIImage* weakImage = [image retain]; // image +1 [weakAsset release]; // asset -1 dispatch_async(dispatch_get_main_queue(), ^(void) { [self.imageView setImage: weakImage]; [weakImage release]; // image -1 }); } }); }
__block
可防止块closures保留asset
和image
使您可以明确地保留/释放它们。 这将意味着你所创造的所有东西,都将被明确处置。 ( rep
和image
大概保留/自动释放,但你的池应该照顾这些)。我相信这是最明确的,你可以这样做,因为asset
被传递给你,因此你不能控制它的存在时间很长,并且它最终是存储在iref
中的CGImageRef的“所有者”(就这个范围而言)。
希望澄清一些事情。
你应该保留CGImageRef
..
CGImageRef iref = CGImageRetain([rep fullScreenImage]); //..before [self.imageView.. CGImageRelease(iref)
剩下的只是一个运行循环的问题,在没有GCD的情况下图像会被释放,另外一个是由GCDpipe理的,但是无论如何都是错误的,有人必须拥有iref的所有权。
- Xcode的 – 我的应用程序崩溃,错误是“无效指针从空闲列表中出列***在malloc_error_break设置断点debugging”
- UIWebView不使用ARC释放所有活动字节
- iOS对手的内存警告
- 调用委托方法,无法识别的select器,因为发送到错误的对象
- iOS下载和parsing大的JSON响应导致CFData(存储)泄漏
- UIGraphicsGetImageFromCurrentImageContext内存泄漏与预览
- 内存警告后,崩溃在iOS上运行OpenGL
- 适用于iPhone OS应用程序的可用内存
- 在UINavigationController中释放ViewControllers的内存