来月に予定されているプロジェクトに、githubtにあるNSData +Base64opensrcライブラリを使用しています。私はプロファイリング、分析、最適化を始めたばかりで、そのコードに起因するリークを発見しました。NSZombieとすべてのデバッグ方法とトライキャッチを無効にしました。これは、以前にそれらがメモリをリークすることがあることを発見したためです。リークが特定される正確な線は次のとおりです。
- (NSString *)base64EncodedString
{
return [self base64EncodedStringWithWrapWidth:0];
}
そして分解:
+0x0 pushl %ebp
+0x1 movl %esp, %ebp
+0x3 subl $24, %esp
+0x6 calll -[NSData(Base64) base64EncodedString]+0xb
+0xb popl %eax
+0xc movl +86389(%eax), %eax
+0x12 movl %eax, +4(%esp)
+0x16 movl +8(%ebp), %eax
+0x19 movl %eax, (%esp)
+0x1c movl $0, +8(%esp)
+0x24 calll DYLD-STUB$$objc_msgSend // 100% leak
+0x29 addl $24, %esp
+0x2c popl %ebp
+0x2d ret
ライブラリまたはコードの他の部分を適切に使用していないことが私のせいである可能性があるため、作成者に連絡していません。
特定の方法を使用する場合(一度だけ使用する場合)、暗号化ルーチンの後に使用します。
+ (NSString *) encryptString:(NSString *)plaintext withKey:(NSString *)key
{
// Convert string-to-be-encrypted to Data
NSData *inData = [Miscellaneous utf8string2data:plaintext];
// Encrypt, Encode, Return
return [[self encryptData:inData withKey:key] base64EncodedString];
}
しかし、メモリがリークしている実際のポイントは、メソッドによって呼び出されているメソッドにあるように感じます。
base64EncodedStringWithWrapWidth
正確な行は次のとおりです。
outputBytes = realloc(outputBytes, outputLength);
NSString *result = [[NSString alloc] initWithBytesNoCopy:outputBytes length:outputLength encoding:NSASCIIStringEncoding freeWhenDone:YES];
だから私の質問は次のとおりだと思います:1)このライブラリを使用して同様の動作を観察した人はいますか2)割り当てが不適切な文字列を使用してリークを引き起こしている可能性があります3)それを解決する方法を知っている人、またはこれを置き換えるために使用できる別のライブラリ?
ありがとう!
編集:Instrumentsがリークコードとして特定する上記の行を次のように変更しました:
outputBytes = realloc(outputBytes, outputLength);
NSString *result = [[NSString alloc] initWithBytes:outputBytes length:outputLength encoding:NSASCIIStringEncoding];
free(outputBytes);
しかし、私はまだそのラインからリークを取得します。ObjectiveCのmalloc/realloc / freeに問題はありますか?
編集2:
Bytes Used # Leaks Symbol Name
512 Bytes 5.2% 2 thread_start
512 Bytes 5.2% 2 _pthread_start
512 Bytes 5.2% 2 __NSThread__main__
512 Bytes 5.2% 2 -[NSThread main]
512 Bytes 5.2% 2 -[Sync get]
512 Bytes 5.2% 2 -[Request DoRequest]
512 Bytes 5.2% 2 -[Request encryptMessage:]
512 Bytes 5.2% 2 +[AES256 encryptString:withKey:]
512 Bytes 5.2% 2 -[NSData(Base64) base64EncodedString]
512 Bytes 5.2% 2 -[NSData(Base64) base64EncodedStringWithWrapWidth:]
512 Bytes 5.2% 2 -[NSPlaceholderString initWithBytes:length:encoding:]
512 Bytes 5.2% 2 CFStringCreateWithBytes
512 Bytes 5.2% 2 __CFStringCreateImmutableFunnel3
512 Bytes 5.2% 2 _CFRuntimeCreateInstance
512 Bytes 5.2% 2 CFAllocatorAllocate
512 Bytes 5.2% 2 __CFAllocatorSystemAllocate
これが誤った警告であるかどうかを識別するのに役立つかどうかはわかりませんが、何もフィルタリングしないことにより、原因はCFAllocatorSystemAllocateのように見えます。
+0x13 calll DYLD-STUB$$malloc_zone_malloc
+0x18 addl $8, %esp
だから私はこれが本当にリークであるかどうかを予約し始めています。ただし、エミュレーターとiPadの両方でデバッグすると同じ結果になります。ARCが使用されており、オブジェクトを参照する代わりにコピーしようとしています。
解決策:リークを発見しました。これは、間違った種類のキャストを使用して不適切に実装されたメソッドにありました(愚かな私はこれを初めて見ませんでした)
return (__bridge_transfer NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
(__bridge_retained CFStringRef)string,
NULL,
(CFStringRef)@"!*'\"();:@&=+$,/?%#[]% ",
CFStringConvertNSStringEncodingToEncoding(encoding));
ここでbridge_retainはARCを1つインクリメントしたため、リリースされていませんでした。そのため、警告が表示されていました。おかしなことに、何が悪いのか気付く前に、それは私が最後に見たコードでした。ご協力ありがとうございました