最近进行iOS 安全黑匣子的测试,在Demo中通过不断的点击调加密接口,同时通过苹果自带instrument的leak工具监控,发现典型的内存泄漏,监控图如下:
上图中红色的部分表示该操作触发的代码有内存泄漏的可能,于是拿出源代码来研究一番,源代码如下:
//加密接口
-(IBAction)encrypt:(id)sender {
out =nil;
NSString *text = @"1374112539taobao://?ssoType=AuthorizeApplicationPrefix&appkey=1234&appName=SSO Demo&urlSchemes=ssodemo://&t=13741125391374112539";
NSData *inputData = [text dataUsingEncoding:NSUTF8StringEncoding];
out = [[[TBSecretMgr sharedInstance] encrypt:inputData]retain];
NSString *test =[[NSString alloc] initWithData:out encoding:NSUTF8StringEncoding];
NSLog(@"encrypt:%@",test);
[test release];}
//解密接口
- (IBAction)deEncrypt:(id)sender {
NSData *deEncryptOut = [[TBSecretMgr sharedInstance] decrypt:out];
NSString *outStr = [[NSString alloc] initWithData:deEncryptOut encoding:NSUTF8StringEncoding];
NSLog(@"deencry%@",outStr);
[outStr release];
}
在分析这2个接口之前,我们需要了解iOS的内存机制,尤其对基本的alloc,retain,release,dealloc需要理解.
alloc 对象分配后引用计数为1
retain 对象的引用计数+1
copy copy一个对象变成新的对象(新内存地址)引用计数为1,原来对象计数不变.
relase 对象引用计数-1,如果为0释放内存
autorelase 对象引用计数-1,如果为0不马上释放.
内存管理的原则就是最终的引用计数要平衡.
如果最后引用计数大于0,则会内存泄漏
如果引用计数等于0还对该对象进行操作,则会出现内存访问失败,crash.
此段代码out返回类型是Nsstring,后加一个retain,在不断的点击下,每次引用,都会retain+1,而没有release操作,导致内存一直被占用,没有释放. 解决方案就是把加解密放在一个操作中,不加retain计数.
代码修改如下,内存泄漏问题解决:
- (IBAction)encrypt:(id)sender {out =nil;NSString *text =nil;NSData *inputData = [text dataUsingEncoding:NSUTF8StringEncoding];out = [[TBSecretMgr sharedInstance] encrypt:inputData];NSString *test =[[NSString alloc] initWithData:out encoding:NSUTF8StringEncoding];NSLog(@"encrypt:%@",test);[test release];NSData *deEncryptOut = [[TBSecretMgr sharedInstance] decrypt:out];NSString *outStr = [[NSString alloc] initWithData:deEncryptOut encoding:NSUTF8StringEncoding];NSLog(@"Dencry%@",outStr);[outStr release];}