我已將我的項目轉換爲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的以下屏幕截圖。
(這裏我有放大的問題,區) 一些能幫助我找到了什麼問題。否則請指導我如何做進一步的分析
是否靜態分析器抱怨? – HAS
不..沒有抱怨。 – nath
'loadPDF:'方法是最有趣的。它有什麼作用? (我懷疑,它保留_pdfFile_,_pdfFile_保留_decryptedMData_。 – CouchDeveloper