首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >UIImageJPEGRepresentation收到内存警告

UIImageJPEGRepresentation收到内存警告
EN

Stack Overflow用户
提问于 2014-08-12 00:44:53
回答 3查看 4.1K关注 0票数 4

我在使用UIImageJPEGRepresentation时收到内存警告,有什么方法可以避免这种情况吗?它不会使应用程序崩溃,但如果可能的话,我想避免它。它间歇性地不运行[[UIApplication sharedApplication] openURL:url];

代码语言:javascript
复制
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    UIImage *image = [info valueForKey:UIImagePickerControllerOriginalImage];
    NSData *imageToUpload = UIImageJPEGRepresentation(image, 1.0);

    // code that sends the image to a web service (omitted)
    // on success from the service
    // this sometime does not get run, I assume it has to do with the memory warning?
    [[UIApplication sharedApplication] openURL:url];
}
EN

回答 3

Stack Overflow用户

发布于 2014-08-12 04:34:24

使用UIImageJPEGRepresentation (其中通过UIImage往返资源)可能会出现问题,因为使用1.0的compressionQuality时,生成的NSData实际上可能比原始文件大得多。(另外,您在UIImage中保存了图像的第二个副本。)

例如,我刚刚从iPhone的图片库中随机挑选了一张图片,原始图片的大小是1.5mb,但由UIImageJPEGRepresentation制作的compressionQuality为1.0的NSData需要6.2mb。而且,在UIImage中保存图像本身可能会占用更多的内存(因为如果未压缩,则可能需要每个像素4个字节)。

相反,您可以使用getBytes方法获取原始资源:

代码语言:javascript
复制
static NSInteger kBufferSize = 1024 * 10;

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
    NSURL *url = info[UIImagePickerControllerReferenceURL];

    [self.library assetForURL:url resultBlock:^(ALAsset *asset) {
        ALAssetRepresentation *representation = [asset defaultRepresentation];
        long long remaining = representation.size;
        NSString *filename  = representation.filename;

        long long representationOffset = 0ll;
        NSError *error;
        NSMutableData *data = [NSMutableData data];

        uint8_t buffer[kBufferSize];

        while (remaining > 0ll) {
            NSInteger bytesRetrieved = [representation getBytes:buffer fromOffset:representationOffset length:sizeof(buffer) error:&error];
            if (bytesRetrieved <= 0) {
                NSLog(@"failed getBytes: %@", error);
                return;
            } else {
                remaining -= bytesRetrieved;
                representationOffset += bytesRetrieved;
                [data appendBytes:buffer length:bytesRetrieved];
            }
        }

        // you can now use the `NSData`

    } failureBlock:^(NSError *error) {
        NSLog(@"assetForURL error = %@", error);
    }];
}

这避免了在UIImage中暂存图像,并且生成的NSData (无论如何对于照片而言)可以小得多。请注意,这也有一个优点,即它还保留了与图像关联的元数据。

顺便说一句,虽然上面的代码代表了显著的内存改进,但您可能会看到一个更显著的内存减少机会:具体地说,您现在可以流式传输资产(子类NSInputStream,以便在需要时使用此getBytes例程获取字节,而不是一次性将整个内容加载到内存中),而不是一次性将整个资产加载到NSData中。这个过程有一些麻烦(请参阅BJ Homer's article on the topic),但如果您希望显著减少内存占用,这就是解决办法。这里有几种方法(BJ的,使用一些临时文件和流媒体,等等),但关键是流媒体可以显着减少你的内存占用。

但是,通过在UIImageJPEGRepresentation中避免使用UIImage (它避免了图像占用的内存以及UIImageJPEGRepresentation产生的更大的NSData ),您也许能够取得相当大的进展。此外,您可能希望确保内存中没有此图像数据的冗余副本(例如,不要将图像数据加载到NSData中,然后为HTTPBody构建第二个NSData ...看看你能不能一举完成)。如果最坏的情况变得更糟,你可以采用流媒体方法。

票数 5
EN

Stack Overflow用户

发布于 2016-07-29 23:06:50

在ARC中:只需将您的代码放在@autoreleasepool的小块中

代码语言:javascript
复制
 @autoreleasepool {
     NSData *data = UIImageJPEGRepresentation(img, 0.5);
     // something with data
}
票数 4
EN

Stack Overflow用户

发布于 2014-08-12 01:38:48

作为格式化和图像的答案。

使用仪器检查由于保留但不是泄漏的内存而导致的泄漏和内存丢失。后者是仍然指向的未使用的内存。在仪器上的分配工具中使用标记生成(堆快照)。

有关使用堆快照查找内存碎片的信息,请参阅:bbum blog

基本上,该方法是运行Instruments allocate工具,获取堆,运行代码的迭代,并重复3到4次获取另一次堆。这将指示在迭代期间分配的和未释放的内存。

要弄清楚结果,请查看各个分配。

如果您需要查看对象的保留位置、释放位置和自动释放位置,请使用仪器:

在仪器中运行,在分配中设置"Record reference counts“on (对于Xcode 5和更低版本,您必须停止记录以设置该选项)。使应用程序运行,停止录制,向下钻取,您将能够看到所有保留、释放和自动释放发生的位置。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25248294

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档