SDWebImage: kernel EXC_RESOURCE exceeded mem limit: ActiveHard 2048 MB (fatal)

New Issue Checklist

Issue Info

Info Value
Platform Name iOS (iPhone XS Max only)
Platform Version 12.1
SDWebImage Version 4.4.3
Integration Method cocoapods
Xcode Version Xcode 10.1
Repro rate all the time (100%), only observed on the iPhone XS Max
Repro with our demo prj No demo project at this time, but can create one later if necessary.
Demo project link No demo project at this time, but can create one later if necessary.

Issue Description and Steps

A portion of our application downloads and displays a list of companies, including their logos. The company information and logo links can be provided by our customers. Our application also prefetches all of the image assets whenever data is downloaded from our server so the app will still be able to display images in the event the user loses their internet connection.

Our prefetch code looks like:

SDWebImagePrefetcher *prefetcher = [SDWebImagePrefetcher sharedImagePrefetcher];
prefetcher.options = prefetcher.options | SDWebImageRetryFailed;
[prefetcher prefetchURLs:[urlSet allObjects]];

Where urlSet is an array of image URLs as NSStrings.

Very occasionally we will have a customer try to use a logo or other image that is very large. For example, this logo which is 37627 × 7644. WARNING: Before clicking on the link, the image will slow down your browser significantly.

Testing the application on an iPod Touch running iOS 10 and an iPhone X running iOS 12 we’re experiencing no issues aside from a slight slowdown and the logo not appearing (the app logs that it can’t allocate the required memory), which is fine. However, when running on the iPhone XS Max the app crashes immediately. This has also only been observed when running on the physical device - the simulator seems to work exactly as the iPod Touch and iPhone X do. The issue has been duplicated on two different iPhone XS Max devices.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 23 (15 by maintainers)

Most upvoted comments

@cdunkel You can using Image IO (for PNG/JPEG/HEIF, Apple’s supported format) for thumb decoding, I test it locally on the iPhone XS Max, it works. The sample code looks like this (written in 4.x’s protocol API). You can create a subclass of SDWebImageIOCoder and override this method instead (Don’t forget to adjust plugin orders in SDWebImageCodersManager).

- (UIImage *)decodedImageWithData:(NSData *)data {
    if (!data) {
        return nil;
    }
    
    CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, nil);
    if (!source) {
        return nil;
    }
    NSDictionary *properties = (__bridge_transfer NSDictionary *)CGImageSourceCopyPropertiesAtIndex(source, 0, nil);
    NSUInteger pixelWidth = [properties[(__bridge NSString *)kCGImagePropertyPixelWidth] unsignedIntegerValue];
    NSUInteger pixelHeight = [properties[(__bridge NSString *)kCGImagePropertyPixelHeight] unsignedIntegerValue];
    NSUInteger exifOrientation = [properties[(__bridge NSString *)kCGImagePropertyOrientation] unsignedIntegerValue];
    if (!exifOrientation) {
        exifOrientation = 1;
    }
    UIImageOrientation imageOrientation = [SDWebImageCoderHelper imageOrientationFromEXIFOrientation:exifOrientation];
    NSUInteger maxPixelSize = 4000; // This should be a option value from the caller method
    
    CGImageRef imageRef;
    if (pixelWidth > maxPixelSize || pixelHeight > maxPixelSize) {
        // Using thumb pixel decoding
        NSDictionary *options = @{(__bridge NSString *)kCGImageSourceCreateThumbnailFromImageIfAbsent : @(YES), (__bridge NSString *)kCGImageSourceThumbnailMaxPixelSize : @(maxPixelSize)};
        imageRef = CGImageSourceCreateThumbnailAtIndex(source, 0, (__bridge CFDictionaryRef)options);
    } else {
        // Using full pixel decoding
        imageRef = CGImageSourceCreateImageAtIndex(source, 0, nil);
    }
    
    UIImage *image = [[UIImage alloc] initWithCGImage:imageRef scale:1 orientation:imageOrientation];
    CGImageRelease(imageRef);
    CFRelease(source);
    image.sd_imageFormat = [NSData sd_imageFormatForImageData:data];
    
    return image;
}

image

However, I need to consider whether it’s suitable to put this feature in our Core Framework on 4.x. Because now our decoder does not support a extra options to pass from the top-level API to the bottom. Maybe if we have to do, we can put it on a property of SDWebImageIOCoder shared instance.

On 5.x, I’ll make this a optional value through decoding option, to allow customization of max limit pixel count during decoding. This can solve some issue.