当我执行的主线程只有以下iref
被立即自动释放:
-(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
立即释放的对象?
以前的研究:
- 泄漏仪器犯规表现出任何泄漏,当我用它记录。
- 该分配仪器显示,
CGImageRef
对象被分配和仍然生活了大约一分钟它应该被释放之后。 - 如果我尝试手动释放
CGImageRef
使用对象CGImageRelease
我得到一分钟后BAD_EXEC例外,当图像试图获得自动释放。 - 保留
iref
使用CGImageRetain
,然后使用CGImageRelease
释放它不工作。 - 计算器上没有帮助类似的问题: 图像加载与GCD , 收到内存警告在创建图像 , 内存泄漏时从alaseet结果GET fullscreenimage ,
首先,有没有一个“自动释放” CF对象的概念。 您可以进入其中,用免费电话桥接类打交道时,这样的事情存在的情况下,但你可以看到,有一个CFRetain
和CFRelease
但没有CFAutorelease
。 所以我认为你曲解的所有权iref
。 让我们来跟踪整个代码所有权:
-(void)loadImage:(ALAsset*)asset{
asset
被传递到该方法。 它保留计数被假定为至少1。
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
块闭合呈现出保留asset
。
@autoreleasepool {
ALAssetRepresentation* rep = [asset defaultRepresentation];
这将返回,通过命名惯例,一个对象,你没有自己。 它可能会自动释放,这可能是一个单身/全局等,但你没有拥有它,而不应通过保留它获得它的所有权。
CGImageRef iref = [rep fullScreenImage];
由于不是一个“自动释放” CF对象的概念,我们将假定rep
正在返回你的内部指针CGImageRef
所拥有的rep
。 您也并不拥有这个,不应该保留它。 与此相关的,你不控制时,它会自行消失。 一个合理的猜测是,它会生活,只要rep
以及合理的推测是, rep
将生活,只要asset
,所以你也许应该假定iref
至少只要将生活作为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];
图像视图是要在采取保留(或复制) image
,如果需要,以完成其工作。
});
内部块执行完毕。 在未来的某个时刻,libdispatch将其释放,这将传递地释放保留采取的块封闭self
和image
。
}
你的自动释放池弹出这里。 这是含蓄地保留/自动释放任何现在应该被释放。
});
外块执行完毕。 在未来的某个时刻,libdispatch将其释放,这将传递地释放挽留采取的块封闭asset
。
}
最终,这种方法无法控制CGImageRef的寿命在iref
因为它从来没有拥有它的所有权。 这里的含义是,CGImageRef是及物动词所拥有asset
,所以它至少会生活,只要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
防止块从封保asset
和image
,让您明确地保留/自己释放他们。 这将意味着所有您所创建的东西,都将被明确地配置。 ( rep
和image
都可能保留/自动释放,但你的池应采取那些照顾。)我相信这是最明确的,你可以了解这个,因为asset
在给你传递,因此你不用管怎么样长时间的生活,这是最终的“所有者”(至于这个范围而言)存储在CGImageRef的iref
。
希望澄清事情有点。
你应该保留CGImageRef
..
CGImageRef iref = CGImageRetain([rep fullScreenImage]);
//..before [self.imageView..
CGImageRelease(iref)
剩下的只是一个运行循环的事情,在一个没有GCD的图像被释放istanneously,在另一种是由GCD管理,但其实是错误不管怎么说,总得有人去Iref的所有权。