我正在githubt找到一个NSData + Base64 opensrc库,用于下个月到期的项目。我刚刚开始分析,分析和优化,并发现了来自该代码的泄漏。我已禁用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)任何人都知道如何解决它,或者我可以用另一个库替换它?
谢谢!
编辑: 我更改了以上几行,仪器精确定位为泄漏代码:
outputBytes = realloc(outputBytes, outputLength);
NSString *result = [[NSString alloc] initWithBytes:outputBytes length:outputLength encoding:NSASCIIStringEncoding];
free(outputBytes);
然而,我仍然从那条线上泄漏。在目标C中是否存在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,因此它没有被释放,这就是我收到警告的原因。有趣的是,在我意识到错误之前,这是我看过的最后一段代码。谢谢你的帮助
答案 0 :(得分:1)
您的分析可能正确,泄漏来自重新分配outputBytes
的地方。但请注意,泄漏的“真正”罪魁祸首是outputBytes
最终没有被释放。问题是为什么它没有被释放。
如果您查看下一行,outputBytes
直接输入NSString
而不复制它指向的字符串的内容,所以我想作者的意图是{从那时起,{1}}将获得NSString
内存块的所有权,outputBytes
负责释放它。当NSString
的引用计数器变为零时,NSString
将释放该块。代码中的下几行显示NSString
变为自动释放:
#if !__has_feature(objc_arc)
[result autorelease];
#endif
如果NSString
是自动发布的,那么一切都应该没问题 - 自动发布池会占用NSString
的所有权,您不必在release
上使用autorelease
你使用它时拥有。上面的代码片段还说只有在编译没有ARC(自动引用计数)的代码时才会调用outputBytes
。所以,我认为代码是正确的,因此NSString
可能被泄露的唯一原因是因为你在某处保留了返回的encryptString
然后忘记释放它。换句话说,泄漏的内存是在你正在使用的库中分配的,但它没有被释放的原因在于库之外,库本身也不能对泄漏负责。
您的encryptString
方法似乎采用编码字符串并将其传递给调用者,而不是在任何地方更改其引用计数,因此您必须继续查看要调用{{1}}的地方看看是否有任何地方你不小心保留了绳子而后来没有松开绳子。