6

मेरे पास एक एआरसी आधारित ऐप है जो एक webservice से लगभग 2,000 काफी बड़ी (1-4 एमबी) बेस 64 एन्कोडेड छवियों को लोड करता है। यह बेस 64 डीकोडेड तारों को .png छवि फ़ाइलों में परिवर्तित करता है और उन्हें डिस्क पर सहेजता है। यह सब एक लूप में किया गया है जहां मुझे कोई भी संदर्भ नहीं होना चाहिए।उद्देश्य सी UIImagePNGRepresentation स्मृति समस्या (एआरसी का उपयोग करके)

मैंने अपना ऐप प्रोफाइल किया और पाया कि UIImagePNGRresentresentेशन लगभग 50% उपलब्ध स्मृति को हॉगिंग कर रहा था।

जिस तरह से मैं इसे देखता हूं, UIImagePNGRepresentation यह छवियों को कैशिंग कर रहा है। इसे ठीक करने का एक तरीका उस कैश को फ्लश करना होगा। कोई विचार है कि कोई ऐसा कैसे कर सकता है?

एक और समाधान UIImagePNGRepresentation के अलावा कुछ और उपयोग करना होगा?

मैंने पहले ही कोई भाग्य के साथ यह कोशिश नहीं की: Memory issue in using UIImagePNGRepresentation। उल्लेख नहीं है कि मैं वास्तव में उपलब्ध समाधान का उपयोग नहीं कर सकता क्योंकि यह मेरे ऐप को बहुत धीमा कर देगा।

यह तरीका है जिसे मैं अपने लूप से कॉल करता हूं। UIImage छवि Base64 से परिवर्तित है:

+ (void)saveImage:(UIImage*)image:(NSString*)imageName:(NSString*)directory { 
    NSData *imageData = UIImagePNGRepresentation(image); //convert image into .png format. 
    NSFileManager *fileManager = [NSFileManager defaultManager]; 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //create an array and store result of our search for the documents directory in it 
    NSString *documentsDirectory = [paths objectAtIndex:0]; //create NSString object, that holds our exact path to the documents directory 
    NSString *pathToFolder = [documentsDirectory stringByAppendingPathComponent:directory]; 

    if (![fileManager fileExistsAtPath:pathToFolder]) { 
    if(![fileManager createDirectoryAtPath:pathToFolder withIntermediateDirectories:YES attributes:nil error:NULL]) { 
     // Error handling removed for brevity 
    } 
    } 

    NSString *fullPath = [pathToFolder stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.png", imageName]]; //add our image to the path 
    [fileManager createFileAtPath:fullPath contents:imageData attributes:nil]; //finally save the path (image) 

    // clear memory (this did nothing to improve memory management) 
    imageData = nil; 
    fileManager = nil; 
} 

संपादित करें: छवि आयाम 1000 * 800 से 3000 * 2000 के लिए मोटे तौर पर बदलती हैं।

उत्तर

4

आप एक autorelease पूल

+ (void)saveImage:(UIImage*)image:(NSString*)imageName:(NSString*)directory { 

    @autoreleasepool 
    { 
     NSData *imageData = UIImagePNGRepresentation(image); //convert image into .png format. 
     NSFileManager *fileManager = [NSFileManager defaultManager]; 
     NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //create an array and store result of our search for the documents directory in it 
     NSString *documentsDirectory = [paths objectAtIndex:0]; //create NSString object, that holds our exact path to the documents directory 
     NSString *pathToFolder = [documentsDirectory stringByAppendingPathComponent:directory]; 

     if (![fileManager fileExistsAtPath:pathToFolder]) { 
      if(![fileManager createDirectoryAtPath:pathToFolder withIntermediateDirectories:YES attributes:nil error:NULL]) { 
      // Error handling removed for brevity 
      } 
     } 

     NSString *fullPath = [pathToFolder stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.png", imageName]]; //add our image to the path 
     [fileManager createFileAtPath:fullPath contents:imageData attributes:nil]; //finally save the path (image) 
    } 
} 

द्वारा विधि शरीर लपेट सकता है लेकिन असल में यह सहायक हो सकता है, अगर आप हमें कुछ और संख्या के साथ प्रदान करते हैं:
क्या आयाम कर छवियों की है। यह महत्वपूर्ण है, क्योंकि छवि डेटा को कच्चे पिक्सल में स्मृति में संग्रहीत किया जाता है। iE एक छवि 2000px width * 2000px height * 4 Bytes (RGBA) ~ 15MB। अब कल्पना करें कि कनवर्ट करने वाले एल्गोरिदम को प्रत्येक पिक्सेल या कम से कम कुछ क्षेत्र के लिए सूचनाएं स्टोर करनी होंगी। बड़ी संख्या की उम्मीद की जा रही है।

+0

मैंने ऑटोरेलीपूल की कोशिश की लेकिन इससे मदद नहीं मिली। कुछ कारणों से ऐप क्रैश हो जाता है जब मैं इसे ऑटोरेलीपूल के साथ प्रोफाइल करने का प्रयास करता हूं .. मैं अपने प्रश्न में छवि आयाम जोड़ दूंगा। – JHollanti

+0

मैंने ऑटोरेलीजपूल चीज़ी को अन्य स्थानों के समूह में जोड़ा और पूरी चीज काम करना शुरू कर दिया। यह शुरू करना बहुत आसान होगा अगर मैं अपने ऐप को प्रोफाइल कर सकता था जब इसमें ऑटोरेलीपूल शामिल थे। @vikingosegundo कभी इस प्रोफाइलिंग मुद्दे था कि मैं सामना कर रहा हूँ? – JHollanti

+0

संख्या। लेकिन मैं अक्सर lldb के साथ मुद्दों को डीबगर और प्रोफाइलिंग कर रहा हूं। मैं वापस जीडीबी स्विच किया। – vikingosegundo

0

क्या डेटा यहां कनवर्ट करना आवश्यक है, शायद इसे डिस्क से लोड पर परिवर्तित करें?

एनएसडीटा ऑब्जेक्ट शायद इसे एनएसएमयूटेबलडेटा बना देता है इस तरह की स्मृति को आवंटित किया जाता है और आवश्यकतानुसार बढ़ता है।

+0

यह एक अच्छा विचार है, लेकिन मेरे पास छवि को एक छवि के रूप में रखना होगा, इसलिए मुझे इसे उन स्थानों में परिवर्तित करने की चिंता करने की आवश्यकता नहीं है जहां मुझे इसका उपयोग करने की आवश्यकता है। – JHollanti

0

आपके पास The ImageIO Framework (पीडीएफ) के साथ बेहतर भाग्य हो सकता है। UIKit की तुलना में स्मृति और कैशिंग पर इसका थोड़ा अधिक नियंत्रण है।

+0

कोई भी पॉइंटर्स Imageio फ्रेमवर्क का उपयोग कर किसी छवि को बेस 64 स्ट्रिंग को कैसे परिवर्तित कर सकता है? – JHollanti

+0

http://cocoawithlove.com/2009/06/base64-encoding- विकल्प-on-mac-and.html?m=1 – EricS

0

इस प्रयास करें:

+ (void)saveImage:(UIImage*)image:(NSString*)imageName:(NSString*)directory { 
    NSData *imageData = UIImagePNGRepresentation(image); //convert image into .png format. 
    CFDataRef imageDataRef = (__bridge_retained CFDataRef) imageData; // ARC fix 
    NSFileManager *fileManager = [NSFileManager defaultManager]; 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //create an array and store result of our search for the documents directory in it 
    NSString *documentsDirectory = [paths objectAtIndex:0]; //create NSString object, that holds our exact path to the documents directory 
    NSString *pathToFolder = [documentsDirectory stringByAppendingPathComponent:directory]; 

    if (![fileManager fileExistsAtPath:pathToFolder]) { 
    if(![fileManager createDirectoryAtPath:pathToFolder withIntermediateDirectories:YES attributes:nil error:NULL]) { 
     // Error handling removed for brevity 
    } 
    } 

    NSString *fullPath = [pathToFolder stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.png", imageName]]; //add our image to the path 
    [fileManager createFileAtPath:fullPath contents:imageData attributes:nil]; //finally save the path (image) 

    // clear memory (this did nothing to improve memory management) 
    imageData = nil; 
    CFRelease(imageDataRef); // ARC fix 
    fileManager = nil; 
} 
1

मैं UIImagePNGRepresentation और एआरसी के साथ एक ही मुद्दा था। मेरा प्रोजेक्ट टाइल्स जेनरेट कर रहा है और UIImagePNGReresentation द्वारा आवंटित स्मृति को तब भी हटाया नहीं गया था जब UIImagePNGRresentation कॉल @autoreleasepool का हिस्सा है।

मुझे भाग्य नहीं मिला कि कुछ और @ ऑटोरेलीजपूल को जोड़कर यह समस्या गायब हो गई है जैसे कि जोहोलंती के लिए किया गया था।

मेरे समाधान Erics विचार पर आधारित है, PNG फ़ाइल को बचाने के लिए ImageIO फ्रेमवर्क का प्रयोग करके:

-(void)saveImage:(CGImageRef)image directory:(NSString*)directory filename:(NSString*)filename { 
@autoreleasepool { 
    CFURLRef url = (__bridge CFURLRef)[NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@", directory, filename]]; 
    CGImageDestinationRef destination = CGImageDestinationCreateWithURL(url, kUTTypePNG, 1, NULL); 
    CGImageDestinationAddImage(destination, image, nil); 

    if (!CGImageDestinationFinalize(destination)) 
     NSLog(@"ERROR saving: %@", url); 

    CFRelease(destination); 
    CGImageRelease(image); 
} 

}

सबसे महत्वपूर्ण है बाद में छवि को रिहा करने का है: CGImageRelease (छवि);

+0

यह पूरी तरह से हमारे मुद्दे को ठीक करता है। –

0

जीथ्यूब के libs का उपयोग करने के संभावित तरीकों में से एक है जो इंटरनेट से UIImage/NSData को डाउनलोड और कैश करता है। यह एसडीवेब इमेज (https://github.com/rs/SDWebImage) या एपीएसमार्टस्टोरेज (https://github.com/Alterplay/APSmartStorage) द्वारा हो सकता है। नवीनतम इंटरनेट से एक छवि प्राप्त करता है और इसे डिस्क पर और स्मृति में स्मार्ट रूप से स्टोर करता है।

0

मैं 3 चैनल छवि (आरजीबी) के बजाय 4 चैनल छवि (आरजीबीए या आरजीबीएक्स) भेजकर इस मुद्दे को हल करता हूं। आप जांच सकते हैं कि आपकी छवि के पैरामीटर बदलने का कोई मौका है या नहीं।

जब आप बेस 64 से UIImage में कनवर्ट करते हैं, तो kCGImageAlphaNone के बजाय kCGImageAlphaNoneSkipLast का उपयोग करने का प्रयास करें।

संबंधित मुद्दे