测试结论
- 常量字符串在正式赋值之前就存在,会保留到整个程序运行期间,无法清除。
- 在调用函数结束的时候NSString字符串才会自动清空,之前都能在内存中搜到。
- 非常量字符串可以通过念茜的CFStringGetCStringPtr的方式清空。(念茜方法详情
只想了解怎么清除NSString的朋友看到这里就够了,下面是以上结论的测试过程。
引子
最近手头的iOS项目对安全性要求非常高。
某个敏感数据使用NSString存储,非常敏感,必须即用即清理。NSString对象会通过ARC自动释放,而并没有显式的清除方法,所以并不能确定自动释放之后内容是否自动清除。
找到念茜博主提供的NSString字符串清除。
为了验证方法有效性,我直接使用念茜的代码试验
_text = @"12dfavkasie";
memset((__bridge voidvoid *)(_text), 0, _text.length - 1);
NSString *myString = [[NSString alloc]initWithFormat:@"information"];
NSLog(@"Origal text : %@ \n",myString); //断点1
“Origal text :”没有显示字符串内容,但是在断点1进行内存扫描依然能搜到一个12dfavkasie。所以为了验证该方法有效性,需要解决如下几个问题。
- 断点1搜到的字符串是常量字符串还是NSString没擦除的结果。
- NSString是否在最后一次调用的时候自动擦除。
- 使用非常量字符串来排除常量字符串干扰,使用这种方法依然能够清除就能证明该方法可以有效清除NSString。
首先建立可以进行内存扫描的iOS环境。
iOS扫描内存过程
- 使用盘古越狱将手头iPhone 4s iOS 7.1.2 越狱。
- 在Cydia上下载OpenSSH。
- 在Cydia上添加源:http://grantdouglas.co.uk 下载 memscan。
- 在MAC上使用SSH连接OpenSSH。
ssh root@192.168.2.199
iPhone手机默认密码为 :alpine
RA手机,修改为:Rongan1234 - 运行iOS中间件工具。
- 用工具名字, 获取iOS工具PID如下:
ps-ax | grep SignTool
ps-ax | grep Mgr - 获取的PID对应进程的内存。
memscan -p 64685 -d -o out4.bin - 搜索获取内存中的数据
grep -c 12345677 out4.bin
得到数据为0,则内存中找不到该字符串。
得到数据不为0,使用grep -a查看该字符串出现的具体位置。
测试过程
编写用于测试的程序验证如下三个问题:
- 断点1搜到的字符串是常量字符串还是NSString没擦除的结果。
通过程序1确定常量字符串的特性。 - NSString是否在最后一次调用的时候自动擦除。
建立两个NSString,确定两个字符串清除的时间。 - 使用非常量字符串来排除常量字符串干扰,使用这种方法依然能够清除就能证明该方法可以有效清除NSString。
常量字符串是否一直存在?
NSString *testStr = [[NSString alloc] initWithFormat:@"14642334"];
NSString *testStr1 = [[NSString alloc] initWithFormat:@"sdfsafd"];
NSString *testStr2 = [[NSString alloc] initWithFormat:@"dsfdsafd"];
NSString *testStr3 = [[NSString alloc] initWithFormat:@"dncmviwmaf"];
NSLog(@"test1");
NSLog(@"test2");
NSLog(@"test1");
NSLog(@"test2");
[testStr compare:testStr1];
[testStr compare:testStr2];
[testStr compare:testStr3];
在该段代码运行之前,用memscan获取内存,用grep -C 10 14642334 获取该字符串附近的上下文,结果如下。
lengthOfBytesUsingEncoding:
getCString:maxLength:encoding:
keyEnumerator
nextObject
test
14642334
sdfsafd
dsfdsafd
dncmviwmaf
test1
test2
当该函数运行结束之后,查找14642334,结果一样。
结论
常量字符串特点如下:
- 集中存储在一个位置。
- 无论代码有没有运行到常量字符串所在位置,内存中都会包含这个字符串的内容。
所以之前念茜代码最后搜到的测试字符串应该是常量字符串。
NSString是否自动清除
测试代码:
unsigned char testByteStr[10];//断点0
testByteStr[0] = '1';//14642334
testByteStr[1] = '4';
testByteStr[2] = '6';
testByteStr[3] = '4';
testByteStr[4] = '2';
testByteStr[5] = '3';
testByteStr[6] = '3';
testByteStr[7] = '4';
NSString *testStr = [[NSString alloc] initWithBytes:testByteStr length:8 encoding:NSASCIIStringEncoding];
testByteStr[0] = '4';//47951438
testByteStr[1] = '7';
testByteStr[2] = '9';
testByteStr[3] = '5';
testByteStr[4] = '1';
testByteStr[5] = '4';
testByteStr[6] = '3';
testByteStr[7] = '8';
NSString *testStr2 =[[NSString alloc] initWithBytes:testByteStr length:8 encoding:NSASCIIStringEncoding];
memset(testByteStr, 0, 8);
NSLog(@"test");//断点1
[testStr compare:testStr2];
NSLog(@"test");//断点2
NSLog(@"%l",testStr.length);
NSLog(@"test");//断点3
testStr = @"123";
NSLog(@"test");//断点4
结果和分析:
断点0时,14642334出现0次,47951438出现0次。
断点1时,14642334出现1次,47951438出现1次。
testByteStr已经用memset清空,所以内存中唯一的14642334是testStr。唯一的47951438是testStr2。
断点2时,14642334出现1次,47951438出现1次。
之后testStr2最后一次调用在断点2前,然而testStr2依然能搜到。所以NSString并没有在最后一次调用时自我清除。
断点3时,14642334出现1次,47951438出现1次。
断点4时,14642334出现1次,47951438出现1次。
断点5为该函数执行结束之后的断点,14642334出现0次,47951438出现0次。
结论
NSString只会在所在函数段结束的时候自动清空。
排除常量字符串干扰,擦除字符串
unsigned char testByteStr[10];//断点0
testByteStr[0] = '1';//14642334
testByteStr[1] = '4';
testByteStr[2] = '6';
testByteStr[3] = '4';
testByteStr[4] = '2';
testByteStr[5] = '3';
testByteStr[6] = '3';
testByteStr[7] = '4';
NSString *testStr = [[NSString alloc] initWithBytes:testByteStr length:8 encoding:NSASCIIStringEncoding];
memset(testByteStr , 0 , 8);
char *str = malloc(9*sizeof(char));//断点1
str = (char *)CFStringGetCStringPtr((CFStringRef)testStr,CFStringGetSystemEncoding());
NSLog(@"test");//断点2
memset(str , 0 , 7);
NSLog(@"test");//断点3
在Xcode里运行测试程序,在程序运行到断点0,1,2,3的时候使用memscan扫描14642334的数量。
断点0结果:0
断点1结果:1
testByteStr已经清空。内存中唯一14642334是testStr。
断点2结果:1
执行CFStringGetCStringPtr之后,内存中依然只有一个14642334。而之前已经试验过testStr字符串在函数结束之后才会清空,所以str指向testStr存储14642334的内存位置。
断点3结果:0
清空str之后,testStr也清空了。
结论
念茜的方法可以有效清空NSString。
测试结论
- 常量字符串在正式赋值之前就存在,会保留到整个程序运行期间,无法清除。
- 在调用函数结束的时候NSString字符串才会自动清空,之前都能在内存中搜到。
- 非常量字符串可以通过CFStringGetCStringPtr的方式清空。
网友评论