Ios imageWithCGImage:GCD内存问题
当我仅在主线程上执行以下操作时,Ios imageWithCGImage:GCD内存问题,ios,objective-c,memory,core-graphics,grand-central-dispatch,Ios,Objective C,Memory,Core Graphics,Grand Central Dispatch,当我仅在主线程上执行以下操作时,iref会立即自动删除: -(void)loadImage:(ALAsset*)asset{ @autoreleasepool { ALAssetRepresentation* rep = [asset defaultRepresentation]; CGImageRef iref = [rep fullScreenImage]; UIImage* image = [UIImage imageWithCGIm
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:WithGCD时,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
- 如果我尝试使用
手动释放CGImageRelease
对象,则当图像尝试自动释放时,一分钟后会出现错误的执行异常CGImageRef
- 使用
保留CGImageRetain
,然后使用iref
释放它是不起作用的CGImageRelease
- 关于stackoverflow的类似问题没有帮助:
剩下的只是一个运行循环问题,在一个没有GCD的系统中,映像是随机发布的,在另一个系统中,映像是由GCD管理的,但无论如何都是错误的,必须有人拥有iref的所有权。您应该保留CGImageRef
剩下的只是一个运行循环的问题,在一个没有GCD的系统中,映像是以静态方式发布的,在另一个系统中,映像是由GCD管理的,但无论如何都是错误的,必须有人取得iref的所有权。首先,没有“自动删除”CF对象的概念。在处理免费桥接类时,您可能会遇到这样的情况,但正如您所看到的,有
CFRetain
和CFRelease
但没有CFAutorelease
。所以我认为你误解了iref
的所有权。让我们在整个代码中跟踪所有权:
-(void)loadImage:(ALAsset*)asset{
资产
被传递到此方法中。假定其保留计数至少为1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
块闭包在资产
上进行保留
@autoreleasepool {
ALAssetRepresentation* rep = [asset defaultRepresentation];
UIImage* image = [UIImage imageWithCGImage:iref
scale:[rep scale]
orientation:UIImageOrientationUp];
通过命名约定,这将返回您不拥有的对象。它可能是自动释放的,也可能是单例/全局的,等等。但您不拥有它,也不应该通过保留它来获得它的所有权
CGImageRef iref = [rep fullScreenImage];
由于没有“自动删除”CF对象的概念,我们假定rep
正在返回一个指向rep
拥有的CGImageRef
的内部指针。你也不拥有它,也不应该保留它。与此相关的是,你无法控制它何时消失。一个合理的猜测是它的寿命与rep
一样长,一个合理的猜测是rep
的寿命与asset
的寿命一样长,因此您可能应该假设iref
的寿命至少与asset
的寿命一样长
@autoreleasepool {
ALAssetRepresentation* rep = [asset defaultRepresentation];
UIImage* image = [UIImage imageWithCGImage:iref
scale:[rep scale]
orientation:UIImageOrientationUp];
如果UIImage需要CGImageRef保留,则需要保留或复制以确保其保持活动状态。(可能是后者)UIImage本身通过命名约定自动删除
dispatch_async(dispatch_get_main_queue(), ^(void) {
此内部块闭合将在图像
(和自身
)上保留。libdispatch将复制该块,并延长这些保留的生命周期,直到执行该块并释放该块
[self.imageView setImage:image];
如果需要,图像视图将在图像
上保留(或复制)以执行其工作
});
内部块执行完毕。在将来的某个时候,libdispatch将释放它,它将在self
和image
上通过块闭包传递释放保留
}
你的自动释放池在这里弹出。任何隐式保留/自动删除的内容都应该立即发布
});
外部块执行完毕。在将来的某个时候,libdispatch将释放它,这将过渡地释放资产上的块闭包所获取的retain
}
最终,此方法无法控制iref
中CGImageRef的生存期,因为它从未拥有它的所有权。这里的含义是CGImageRef是由资产
过渡性拥有的,因此它的寿命至少与资产
一样长。由于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
});
}
});
}
\uu block
防止块闭包保留资产
和图像
,允许您自己明确保留/释放它们。这意味着,在您创建的所有内容中,所有内容都将被显式地处理。(rep
和image
可能是保留/自动删除的,但您的池应该负责这些。)我相信这是您对此最明确的解释,因为资产
是传递给您的,因此您无法控制它的寿命,它最终是“所有者”(就这个范围而言)存储在iref
中的CGImageRef的
希望这能澄清一些问题。首先,没有“自动删除”CF对象的概念。在处理免费桥接类时,您可能会遇到这样的情况,但正如您所看到的,有CFRetain
和CFRelease
但没有CFAutorelease
。所以我认为你误解了iref
的所有权。让我们在整个代码中跟踪所有权:
-(void)loadImage:(ALAsset*)asset{
资产
被传递到此方法中。假定其保留计数至少为1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
块闭包在资产
上进行保留
@autoreleasepool {
ALAssetRepresentation* rep = [asset defaultRepresentation];
UIImage* image = [UIImage imageWithCGImage:iref
scale:[rep scale]
orientation:UIImageOrientationUp];
通过命名修道院,这将返回您