imageWithCGImage:GCD内存问题(imageWithCGImage: GCD mem

2019-09-26 18:42发布

当我执行的主线程只有以下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 ,

Answer 1:

首先,有没有一个“自动释放” CF对象的概念。 您可以进入其中,用免费电话桥接类打交道时,这样的事情存在的情况下,但你可以看到,有一个CFRetainCFRelease但没有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将其释放,这将传递地释放保留采取的块封闭selfimage

        }

你的自动释放池弹出这里。 这是含蓄地保留/自动释放任何现在应该被释放。

    });

外块执行完毕。 在未来的某个时刻,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防止块从封保assetimage ,让您明确地保留/自己释放他们。 这将意味着所有您所创建的东西,都将被明确地配置。 ( repimage都可能保留/自动释放,但你的池应采取那些照顾。)我相信这是最明确的,你可以了解这个,因为asset在给你传递,因此你不用管怎么样长时间的生活,这是最终的“所有者”(至于这个范围而言)存储在CGImageRef的iref

希望澄清事情有点。



Answer 2:

你应该保留CGImageRef
..

CGImageRef iref = CGImageRetain([rep fullScreenImage]);
//..before [self.imageView..
CGImageRelease(iref)

剩下的只是一个运行循环的事情,在一个没有GCD的图像被释放istanneously,在另一种是由GCD管理,但其实是错误不管怎么说,总得有人去Iref的所有权。



文章来源: imageWithCGImage: GCD memory issue