內存管理(二)

上一篇我們簡單的介紹了NSTimer、NSProxy、GCD定時器、自定義time、iOS程序的內存布局、Tagged Pointer、copy和mutableCopy等,下面我們繼續看看內存的管理
Demo代碼可見MemoryManagement


自定義copy

YDPerson.h
#import <Foundation/Foundation.h>
@interface YDPerson : NSObject<NSCopying>
@property (assign, nonatomic) int age;
@property (assign, nonatomic) double height;
@end

YDPerson.m
#import "YDPerson.h"
@implementation YDPerson
- (id)copyWithZone:(NSZone *)zone{
    YDPerson *person = [[YDPerson allocWithZone:zone] init];
    person.age = self.age;
//    person.weight = self.weight;
    person.height = 180.0f;
    return person;
}

- (NSString *)description{
    return [NSString stringWithFormat:@"age = %d, weight = %f", self.age, self.height];
}
@end

YDPerson *p = [[YDPerson alloc]init];
p.age = 18;
p.height = 200.0f;
NSLog(@"p.age = %d  p.height = %f",p.age,p.height);
    
YDPerson *p1 = [p copy];
NSLog(@"p1.age = %d  p1.height = %f",p1.age,p1.height);

打印:
MemoryManagement[31345:1581114] p.age = 18  p.height = 200.000000
MemoryManagement[31345:1581114] p1.age = 18  p1.height = 180.000000

引用計數的存儲

詳見runtime源碼:NSObject.mm

memoryManagerment_13.png

weak對象銷毀

MyPerson.h
#import <Foundation/Foundation.h>
@interface MyPerson : NSObject
@end

MyPerson.m
#import "MyPerson.h"
@implementation MyPerson
-(void)dealloc{
    NSLog(@"%s",__FUNCTION__);
}
@end

__strong MyPerson *p1;
NSLog(@"111");
{
   MyPerson *person = [[MyPerson alloc]init];
   p1 = person;
}
NSLog(@"222");

打印:
MemoryManagement[31529:1592495] 111
MemoryManagement[31529:1592495] 222
MemoryManagement[31529:1592495] -[MyPerson dealloc]

===============================
__weak MyPerson *p2;
NSLog(@"111");
{
  MyPerson *person = [[MyPerson alloc]init];
  p2 = person;
}
NSLog(@"222");

打印:
MemoryManagement[31576:1595781] 111
MemoryManagement[31576:1595781] -[MyPerson dealloc]
MemoryManagement[31576:1595781] 222

================================
__unsafe_unretained MyPerson *p3;
NSLog(@"111");
{
    MyPerson *person = [[MyPerson alloc]init];
    p3 = person;
}
NSLog(@"222");

打印:
MemoryManagement[31670:1603150] 111
MemoryManagement[31670:1603150] -[MyPerson dealloc]
MemoryManagement[31670:1603150] 222

從runtime的底層源碼可見:

memoryManagerment_14.png
memoryManagerment_15.png
  • weak對象銷毀會自動將其指的對象置為nil
  • obj->clearDeallocating();會根據當前對象的地址值,然后通過hash查找到當前的引用計數和弱引用(弱引用表 ),將弱引用清除掉

dealloc

memoryManagerment_16.png

具體的見上流程圖(weak)


自動釋放池

#import <Foundation/Foundation.h>
#import "myPerson.h"

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        myPerson *person = [[[myPerson alloc] init] autorelease];
        NSLog(@"%@",person);
    }
    return 0;
}

查看源碼,打斷點objc4-750

可以看到下面的圖:


memoryManagerment_17.png

AutoreleasePoolPage的結構

memoryManagerment_18.png
memoryManagerment_19.png
memoryManagerment_20.png
memoryManagerment_21.png

Runloop和Autorelease

memoryManagerment_22.png
- (void)viewDidLoad {
    [super viewDidLoad];
    NSObject *obj = [[[NSObject alloc]init] autorelease];
    NSLog(@"%@",[NSRunLoop mainRunLoop]);
}

打印:
截取其中關于:AutoreleasePool

    "<CFRunLoopObserver 0x6000036406e0 [0x10c5b7b68]>{valid = Yes, activities = 0x1, repeats = Yes, order = -2147483647, callout = _wrapRunLoopWithAutoreleasePoolHandler (0x114c601b1), context = <CFArray 0x60000090c7b0 [0x10c5b7b68]>{type = mutable-small, count = 1, values = (\n\t0 : <0x7fcf47800058>\n)}}",
    "<CFRunLoopObserver 0x6000036405a0 [0x10c5b7b68]>{valid = Yes, activities = 0xa0, repeats = Yes, order = 2147483647, callout = _wrapRunLoopWithAutoreleasePoolHandler (0x114c601b1), context = <CFArray 0x60000090c7b0 [0x10c5b7b68]>{type = mutable-small, count = 1, values = (\n\t0 : <0x7fcf47800058>\n)}}"

其中:activities的類型為:
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0),
    kCFRunLoopBeforeTimers = (1UL << 1),
    kCFRunLoopBeforeSources = (1UL << 2),
    kCFRunLoopBeforeWaiting = (1UL << 5),
    kCFRunLoopAfterWaiting = (1UL << 6),
    kCFRunLoopExit = (1UL << 7),
    kCFRunLoopAllActivities = 0x0FFFFFFFU
};

activities = 0x1:kCFRunLoopEntry 監聽RunLoop對象進入循環的事件
activities = 0xa0:kCFRunLoopBeforeWaiting|kCFRunLoopExit 監聽RunLoop即將進入休眠和RunLoop對象退出循環的事件

程序運行后產生的兩個CFRunLoopObserver一個監聽RunLoop對象進入循環的事件,執行回調函數_wrapRunLoopWithAutoreleasePoolHandler,并且優先級order為-2147483647即32位整數的最小值,保證了它的優先級最高。在回調內會調用_objc_autoreleasePoolPush函數來創建AutoreleasePool,由于它的優先級最高,所以能夠保證自動釋放池在其他回調執行前得到創建。

另一個監聽器監聽RunLoop對象進入休眠和退出循環的事件,回調函數同樣是_wrapRunLoopWithAutoreleasePoolHandler,而優先級為2147483647即32位整數的最大值,保證它的優先級最低。對于監聽進入休眠狀態時回調函數內首先會調用_objc_autoreleasePoolPop函數來釋放AutoreleasePool然后使用_objc_autoreleasePoolPush函數重新創建一個自動釋放池。優先級最低保證了釋放操作是在其他所有回調執行之后發生


autoreleasePool到底是什么時機創建和釋放?
- 當開啟或者喚醒runloop的時候,會創建一個autoreleasePool;
- kCFRunLoopBeforeWaiting | kCFRunLoopExit當runloop睡眠之前或者退出runloop的時候會釋放autoreleasePool;


//結論
- (void)viewDidLoad {
    [super viewDidLoad];
    
    // 這個Person什么時候調用release,是由RunLoop來控制的
    // 它可能是在某次RunLoop循環中,RunLoop休眠之前調用了release
        Person *person = [[[Person alloc] init] autorelease];
     
    Person *person = [[Person alloc] init];ARC下,會出這個大括號就被釋放了,主動調用了. [ person release];
    NSLog(@"%s", __func__);  
}

友情鏈接:

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,406評論 6 538
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,034評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,413評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,449評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,165評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,559評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,606評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,781評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,327評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,084評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,278評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,849評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,495評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,927評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,172評論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,010評論 3 396
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,241評論 2 375