自動釋放池什么時候創建,什么時候銷毀?
運行循環結束前會釋放自動釋放池,還有就是池子滿了,也會銷毀。
面試題
下面代碼存在內存問題么?如果存在如何解決?為什么
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
int lagerNum = 1024 * 1024 * 2 ;
for(int i = 0 ; i < lagerNum; i++)
{
NSString *str = [NSString stringWithFormat:@"Hello"];
str = [str uppercaseString];
str = [NSString stringByAppendingFormat:@"-%@",@"World!"];
}
}
解題思路:首先根據類方法創建的,而且他們都用的是類方法,類方法是每次調用,每次都會為你創建一個新的對象。還有就是通過對象方法創建的對象,如果不是通過alloc new retain copy 創建的對象,那么他們內部都有一個autorelease.(可以通過NSLog(@"%p",str),查看每次調用過后的內存地址,他們的內存地址是不一樣的),他們都是通過自動釋放池進行自動釋放的,所以這些字符串對象會等到循環結束時才會進行釋放,而此時它們會消耗大量的內存資源,所以她們存在內存問題。---通過xcode查看內存峰值就可以看出運行時的變化
解決辦法:從題中看出每次循環這個對象就不會再調用了,所以,我們可以將每一次循環放入到自動釋放池中去,這樣每次循環結束后變會將此次創建的對象銷毀,如下代碼
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
int lagerNum = 1024 * 1024 * 2 ;
for(int i = 0 ; i < lagerNum; i++)
{
@autoreleasepool{
NSString *str = [NSString stringWithFormat:@"Hello"];
str = [str uppercaseString];
str = [NSString stringByAppendingFormat:@"-%@",@"World!"];
}
}
}
------考慮到lagerNum這個數據足夠大,所以我們在內部創建自動釋放池,如果lagerNum不足夠大,那么我們可以在for循環外面創建自動釋放池。
默認主線的運行循環(runloop)是開啟的,子線程的運行循環(runloop)默認是不開啟的,也就意味着子線程中不會創建autoreleasepool,所以需要我們自己在子線程中創建一個自動釋放池。(子線程里面使用的類方法都是autorelease,就會沒有池子可釋放,也就意味着后面沒有辦法進行釋放,造成內存泄漏。)----在主線程中如果產生事件那么runloop才回去創建autoreleasepool,通過這個道理我們就知道為什么子線程中不會創建自動釋放池了,因為子線程的runloop默認是關閉的,所以他不會自動創建autoreleasepool,需要我們手動添加。