1

我已將我的項目轉換爲ARC。後來,我發現與我正在加載的PDF相關的內存泄漏。實際發生的情況是,當我回來時,一旦從導航控制器彈出PDF視圖,內存就無法正常釋放。然後我使用Instrument來查看哪些代碼行負責此內存泄漏。NSMutableData的內存問題

在下面我已經解釋了發生了什麼。

首先我檢查我的pdf是否加密(它是加密的)。使用delegate.That方法:然後我解密使用StringEncryption類

StringEncryption *crypto = [[StringEncryption alloc]init]; 
self.stringEncryption = crypto; 
[self.stringEncryption setDelegate:self]; 
NSData *encryptedPDFData = [NSData dataWithContentsOfFile:pdfPath]; 
[crypto decryptUsingBGProcess:encryptedPDFData key:[key dataUsingEncoding:NSUTF8StringEncoding]]; 

decryptUsingBGProcess方法如下

@autoreleasepool {{ 
    CCOptions padding = kCCOptionPKCS7Padding; 
    NSMutableData *decryptedData =[self doCipher:plainText key:aSymmetricKey context:kCCDecrypt padding:&padding ]; 
    if(!decryptedData)NSLog(@"0001 , EVT,%@, %@,Decryption failed ",[[self class] description],NSStringFromSelector(_cmd)); 
    if(delegate && [delegate respondsToSelector:@selector(decryptionCompleted:)]){ 
     if([delegate isKindOfClass:[PDFAnnotationSampleViewController class]]) 
      [((PDFAnnotationSampleViewController*)delegate) performSelectorOnMainThread:@selector(decryptionCompleted:) withObject:decryptedData waitUntilDone:NO]; 
     else [delegate decryptionCompleted:decryptedData]; 
    } 
} 

docyper方法如下

- (NSMutableData *)doCipher:(NSData *)plainText key:(NSData *)aSymmetricKey 
      context:(CCOperation)encryptOrDecrypt padding:(CCOptions *)pkcs7 
{ 
    CCCryptorStatus ccStatus = kCCSuccess; 
    // Symmetric crypto reference. 
    CCCryptorRef thisEncipher = NULL; 
    // Cipher Text container. 
    NSMutableData * cipherOrPlainText = nil; 
    // Pointer to output buffer. 
    uint8_t * bufferPtr = NULL; 
    // Total size of the buffer. 
    size_t bufferPtrSize = 0; 
    // Remaining bytes to be performed on. 
    size_t remainingBytes = 0; 
    // Number of bytes moved to buffer. 
    size_t movedBytes = 0; 
    // Length of plainText buffer. 
    size_t plainTextBufferSize = 0; 
    // Placeholder for total written. 
    size_t totalBytesWritten = 0; 
    // A friendly helper pointer. 
    uint8_t * ptr; 

    // Initialization vector; dummy in this case 0's. 
    uint8_t iv[kChosenCipherBlockSize]; 
    memset((void *) iv, 0x0, (size_t) sizeof(iv)); 

    //NSLog(@"doCipher: plaintext: %@", plainText); 
    NSLog(@"doCipher: key length: %d", [aSymmetricKey length]); 

    plainTextBufferSize = [plainText length]; 

    //LOGGING_FACILITY(plainTextBufferSize > 0, @"Empty plaintext passed in."); 

    NSLog(@"pkcs7: %d", *pkcs7); 
    // We don't want to toss padding on if we don't need to 
    if(encryptOrDecrypt == kCCEncrypt) { 
     if(*pkcs7 != kCCOptionECBMode) { 
      if((plainTextBufferSize % kChosenCipherBlockSize) == 0) { 
       *pkcs7 = 0x0000; 
      } else { 
       *pkcs7 = kCCOptionPKCS7Padding; 
      } 
     } 
    } else if(encryptOrDecrypt != kCCDecrypt) { 
     NSLog(@"Invalid CCOperation parameter [%d] for cipher context.", *pkcs7); 
    } 

    // Create and Initialize the crypto reference. 
    ccStatus = CCCryptorCreate(encryptOrDecrypt, 
           kCCAlgorithmAES128, 
           *pkcs7, 
           (const void *)[aSymmetricKey bytes], 
           kChosenCipherKeySize, 
           (const void *)iv, 
           &thisEncipher 
           ); 

    //LOGGING_FACILITY1(ccStatus == kCCSuccess, @"Problem creating the context, ccStatus == %d.", ccStatus); 

    // Calculate byte block alignment for all calls through to and including final. 
    bufferPtrSize = CCCryptorGetOutputLength(thisEncipher, plainTextBufferSize, true); 

    // Allocate buffer. 
    bufferPtr = malloc(bufferPtrSize * sizeof(uint8_t)); 

    // Zero out buffer. 
    memset((void *)bufferPtr, 0x0, bufferPtrSize); 

    // Initialize some necessary book keeping. 

    ptr = bufferPtr; 

    // Set up initial size. 
    remainingBytes = bufferPtrSize; 

    // Actually perform the encryption or decryption. 
    ccStatus = CCCryptorUpdate(thisEncipher, 
           (const void *) [plainText bytes], 
           plainTextBufferSize, 
           ptr, 
           remainingBytes, 
           &movedBytes 
           ); 

    //LOGGING_FACILITY1(ccStatus == kCCSuccess, @"Problem with CCCryptorUpdate, ccStatus == %d.", ccStatus); 

    // Handle book keeping. 
    ptr += movedBytes; 
    remainingBytes -= movedBytes; 
    totalBytesWritten += movedBytes; 

    // Finalize everything to the output buffer. 
    ccStatus = CCCryptorFinal(thisEncipher, 
           ptr, 
           remainingBytes, 
           &movedBytes 
          ); 

    totalBytesWritten += movedBytes; 

    if(thisEncipher) { 
     (void) CCCryptorRelease(thisEncipher); 
     thisEncipher = NULL; 
    } 

    if (ccStatus == kCCSuccess) 
     cipherOrPlainText = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)totalBytesWritten]; 
    else 
     cipherOrPlainText = nil; 

    if(bufferPtr) free(bufferPtr); 

    return cipherOrPlainText; 

} 


// this added by David 
- (NSData*) md5data: (NSString *) str 
{ 
    const char *cStr = [str UTF8String]; 
    unsigned char result[CC_MD5_DIGEST_LENGTH]; 
    CC_MD5(cStr, strlen(cStr), result); 
    NSString* temp = [NSString stringWithFormat: 
      @"02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", 
      result[0], result[1], result[2], result[3], result[4], 
      result[5], result[6], result[7], 
      result[8], result[9], result[10], result[11], result[12], 
      result[13], result[14], result[15] 
      ]; 
    return [NSData dataWithBytes:[temp UTF8String] length:[temp length]]; 

} 

decrpting它之後調用decryptionCompleted方法如下

-(void)decryptionCompleted:(NSData*)decryptedData{ 
    /* PDF has decrypted successfully */ 
    NSLog(@"0403 , EVT,%@, %@,Paper is Decrypted successfuly ",[[self class] description],NSStringFromSelector(_cmd)); 
    NSMutableData *decryptedMData = [[NSMutableData alloc] initWithData:decryptedData]; 
    APPDFDocument *pdfFile = [[APPDFDocument alloc] initWithPDFData:decryptedMData information:self.pdfInfo]; 
    self.passwordEncrypted = [pdfFile isEncrypted]; 
    NSLog(@"0404 , EVT,%@, %@,Paper is Decrypted paper has password encryption = %@ ",[[self class] description],NSStringFromSelector(_cmd),[email protected]"YES":@"NO"); 
    [self loadPDF:pdfFile]; 
} 

這裏是顯示內存泄漏發生的地方。請參閱Profiler的以下屏幕截圖。

enter image description here

(這裏我有放大的問題,區) enter image description here 一些能幫助我找到了什麼問題。否則請指導我如何做進一步的分析

+0

是否靜態分析器抱怨? – HAS

+0

不..沒有抱怨。 – nath

+0

'loadPDF:'方法是最有趣的。它有什麼作用? (我懷疑,它保留_pdfFile_,_pdfFile_保留_decryptedMData_。 – CouchDeveloper

回答

0

嘗試這樣的:

NSMutableData *decryptedMData = [decryptedData mutableCopy]; 

而且也把這個方法裏面的自動釋放塊太像這樣:

-(void)decryptionCompleted:(NSData*)decryptedData{ 
@autoreleasepool{ 
     /* PDF has decrypted successfully */ 
     NSLog(@"0403 , EVT,%@, %@,Paper is Decrypted successfuly ",[[self class] description],NSStringFromSelector(_cmd)); 
     NSMutableData *decryptedMData = [[NSMutableData alloc] initWithData:decryptedData]; 
     APPDFDocument *pdfFile = [[APPDFDocument alloc] initWithPDFData:decryptedMData information:self.pdfInfo]; 
     self.passwordEncrypted = [pdfFile isEncrypted]; 
     NSLog(@"0404 , EVT,%@, %@,Paper is Decrypted paper has password encryption = %@ ",[[self class] description],NSStringFromSelector(_cmd),[email protected]"YES":@"NO"); 
     [self loadPDF:pdfFile]; 
} 
} 
+0

沒有運氣的兄弟,問題仍然存在 – nath

+0

仍然沒有運氣我添加了autoreleasepool模塊但是問題仍然存在 – nath

+0

當你到達這個模塊時你有任何的崩潰嗎你是否同時多次調用這個模塊 – Ganapathy