1

我尝试修改 FGallery (https://github.com/gdavis/FGallery-iPhone)。我需要它来从相机胶卷中读取图像,但我遇到了内存泄漏。

旧代码(路径是文件位置):

@autoreleasepool {

NSString *path = [NSString stringWithFormat:@"%@/%@", [[NSBundle mainBundle]   bundlePath],_thumbUrl];
_thumbnail = [UIImage imageWithContentsOfFile:path];
_hasThumbLoaded = YES;
_isThumbLoading = NO;
[self performSelectorOnMainThread:@selector(didLoadThumbnail) withObject:nil   waitUntilDone:YES];
}

我的代码(路径是断言库 url):

@autoreleasepool {

ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset) {
   ALAssetRepresentation *rep = [myasset defaultRepresentation];
   CGImageRef iref = [rep fullResolutionImage];
   if (iref) {
       _thumbnail = [UIImage imageWithCGImage:iref];
       _hasThumbLoaded = YES;
       _isThumbLoading = NO;
       [self performSelectorOnMainThread:@selector(didLoadThumbnail) withObject:nil   waitUntilDone:YES];
   }
};        

ALAssetsLibraryAccessFailureBlock failureblock  = ^(NSError *myerror) {
   NSLog(@"booya, cant get image - %@",[myerror localizedDescription]);
};     

NSURL *asseturl = [NSURL URLWithString:_thumbUrl];
[assetslibrary assetForURL:asseturl 
resultBlock:resultblock
failureBlock:failureblock];
}
}

对于相同的图像,我得到了一个很大的内存分配(-didReceiveMemoryWarning),这会使我的代码中的程序崩溃,但在使用原始代码时不会。

任何想法为什么?

PS 我使用 ARC,并为 FGallery 进行了自动转换。它适用于本地应用程序图像,但如前所述,我无法使其适用于相机胶卷图像。

编辑1:程序崩溃

4

4 回答 4

6

我想我明白了。“ALAssetsLibraryAssetForURLResultBlock 结果块”在不同的线程上运行。所以“@autoreleasepool”不适用于它。(每个线程都有自己的自动释放池)。因此,由于大量“自动释放”分配(图像),内存占用要高得多。在块内添加“@autoreleasepool”可以阻止崩溃和大内存分配。

简而言之:

ALAssetsLibraryAssetForURLResultBlock resultblock = ^(ALAsset *myasset) {
   @autoreleasepool {
      ALAssetRepresentation *rep = [myasset defaultRepresentation];
      CGImageRef iref = [rep fullResolutionImage];
      if (iref) {
          _thumbnail = [UIImage imageWithCGImage:iref];
          _hasThumbLoaded = YES;
          _isThumbLoading = NO;
          [self performSelectorOnMainThread:@selector(didLoadThumbnail) withObject:nil   waitUntilDone:YES];
       }
   }
}; 

感谢所有回复的人。

于 2012-02-23T07:05:57.830 回答
4

除非需要全分辨率图像,否则最好使用:

CGImageRef iref = [rep fullScreenImage];

此调用返回适合于全屏显示的表示的 CGImage,而不是最大、最好的可用表示,未以任何方式进行调整。

这样做将节省大量内存。

于 2012-02-22T22:51:53.627 回答
0

获得内存警告 (-didReceiveMemoryWarning) 与内存泄漏不同。它只是意味着您分配了很多内存,并且它给系统施加了压力,操作系统将其解释为可能很快发生的潜在问题。

当您有未释放的未引用对象时会发生内存泄漏。您可以使用编译器分析工具来查看潜在泄漏的位置。这不会找到所有的,所以你可以使用仪器来查看其他可能发生的地方。但是,在您使用这些工具检查之前,您不能肯定地说您有通过查看代码不明显的泄漏。

您没有提到您的代码是否崩溃,但如果是,则不一定是由于内存泄漏。当操作系统决定必须删除某些内容以减少内存压力时,可能会发生这种情况。

更新

显示类 ALAssetRepresentation 的代码。你可能不会在那里释放一些东西。

于 2012-02-22T18:33:18.830 回答
0

正如用户Picciano在他的帖子中提到的,如果可能,您应该使用[rep fullScreenImage];调用而不是请求全尺寸图像。这将节省大量空间。但是,在我的情况下这是不可能的,因为我需要稍后将更高分辨率的图像发送到外部服务器。您可以做的是使用比例尽可能地调整它的大小:

CGFloat originalRatio = assetRepresentation.dimensions.width / assetRepresentation.dimensions.height;
CGFloat wantedRatio = maxSize.width / maxSize.height;
CGFloat scale = 1;

if (originalRatio < wantedRatio)
{
    scale = maxSize.height / assetRepresentation.dimensions.height;
}
else
{
    scale = maxSize.width / assetRepresentation.dimensions.width;
}

CGImageRef ref = [assetRepresentation fullResolutionImage];
UIImage *image = [UIImage imageWithCGImage:ref
                                     scale:scale orientation:orientation];

这基本上决定了我们可以缩放图像的数量(由 定义maxSize)。这为我们节省了足够的时间来防止内存泄漏。

于 2015-03-16T13:39:22.913 回答