iOS內(nèi)存管理機(jī)制詳解

機(jī)制

OC采用引用計數(shù)器對內(nèi)存進(jìn)行管理,當(dāng)一個對象的引用計數(shù)(retainCount)為0,則被釋放塌西。


引用計數(shù)分為兩種:

  • 手動引用計數(shù)(MRC)
// MRC代碼
NSObject * obj = [[NSObject alloc] init]; //引用計數(shù)為1

//不需要的時候
[obj release] //引用計數(shù)減1

//持有這個對象
[obj retain] //引用計數(shù)加1

//放到AutoReleasePool
[obj autorelease]//在auto release pool釋放的時候蛙紫,引用計數(shù)減1
  • 自動引用計數(shù)(ARC)

比如如下ARC代碼:

NSObject * obj;
{
    obj = [[NSObject alloc] init]; //引用計數(shù)為1
}
NSLog(@"%@",obj);

OC的內(nèi)存機(jī)制可以簡單概括為:誰持有(retain)誰釋放(release)皂股。retain引用計數(shù)+1劈猪,release反之昧甘。

我們先看看那ratain和release內(nèi)部是如何實現(xiàn)的。

retain

- (id)retain {
    return ((id)self)->rootRetain();
}

inline id objc_object::rootRetain()
{
    if (isTaggedPointer()) return (id)this;
    return sidetable_retain();
}

可以看出retain底層是調(diào)用了sidetable_retain()

id objc_object::sidetable_retain()
{
#if SUPPORT_NONPOINTER_ISA
    assert(!isa.nonpointer);
#endif
    SideTable& table = SideTables()[this];//獲取引用計數(shù)表
    
    table.lock(); // 加鎖
    size_t& refcntStorage = table.refcnts[this]; // 根據(jù)對象的引用計數(shù)
    if (! (refcntStorage & SIDE_TABLE_RC_PINNED)) {
        refcntStorage += SIDE_TABLE_RC_ONE;
    }
    table.unlock(); // 解鎖

    return (id)this;
}

SideTable數(shù)據(jù)結(jié)構(gòu):

struct SideTable {
    spinlock_t slock;
    RefcountMap refcnts;
    weak_table_t weak_table;

    // 省略...
};

通過代碼可以出战得,SideTable擁有一個自旋鎖充边,一個引用計數(shù)map。這個引用計數(shù)的map以對象的地址作為key常侦,引用計數(shù)作為value

release

- (oneway void)release {
    ((id)self)->rootRelease();
}

inline bool objc_object::rootRelease()
{
    if (isTaggedPointer()) return false;
    return sidetable_release(true);
}
uintptr_t objc_object::sidetable_release(bool performDealloc)
{
#if SUPPORT_NONPOINTER_ISA
    assert(!isa.nonpointer);
#endif
    SideTable& table = SideTables()[this];

    bool do_dealloc = false;

    table.lock(); // 加鎖
    RefcountMap::iterator it = table.refcnts.find(this); // 先找到對象的地址
    if (it == table.refcnts.end()) {
        do_dealloc = true; //引用計數(shù)小于閾值浇冰,最后執(zhí)行dealloc
        table.refcnts[this] = SIDE_TABLE_DEALLOCATING;
    } else if (it->second < SIDE_TABLE_DEALLOCATING) {
        // SIDE_TABLE_WEAKLY_REFERENCED may be set. Don't change it.
        do_dealloc = true;
        it->second |= SIDE_TABLE_DEALLOCATING;
    } else if (! (it->second & SIDE_TABLE_RC_PINNED)) {
        it->second -= SIDE_TABLE_RC_ONE; //引用計數(shù)減去1
    }
    table.unlock(); // 解鎖
    if (do_dealloc  &&  performDealloc) {
        ((void(*)(objc_object *, SEL))objc_msgSend)(this, SEL_dealloc);
    }
    return do_dealloc;
}

release過程:查找map,對引用計數(shù)減1聋亡,如果引用計數(shù)小于閾值肘习,則調(diào)用SEL_dealloc


自己生成的對象,自己持有

使用以下名稱開頭的方法意味著生成的對象會被自己持有坡倔,也就是內(nèi)部會對象進(jìn)行一次retain:

  • alloc
  • new
  • copy
  • mutableCopy

比如NSObject的alloc方法:

+ (id)alloc {
    return _objc_rootAlloc(self);
}

// Base class implementation of +alloc. cls is not nil.
// Calls [cls allocWithZone:nil].
id
_objc_rootAlloc(Class cls)
{
    return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}

// Call [cls alloc] or [cls allocWithZone:nil], with appropriate 
// shortcutting optimizations.
static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
    if (slowpath(checkNil && !cls)) return nil;

#if __OBJC2__
    if (fastpath(!cls->ISA()->hasCustomAWZ())) {
        // No alloc/allocWithZone implementation. Go straight to the allocator.
        // fixme store hasCustomAWZ in the non-meta class and 
        // add it to canAllocFast's summary
        if (fastpath(cls->canAllocFast())) {
            // No ctors, raw isa, etc. Go straight to the metal.
            bool dtor = cls->hasCxxDtor();
            id obj = (id)calloc(1, cls->bits.fastInstanceSize()); // 在這里漂佩,obj創(chuàng)建的時候,obj的retainCount = 1
            if (slowpath(!obj)) return callBadAllocHandler(cls);
            obj->initInstanceIsa(cls, dtor);
            return obj;
        }
        else {
            // Has ctor or raw isa or something. Use the slower path.
            id obj = class_createInstance(cls, 0);
            if (slowpath(!obj)) return callBadAllocHandler(cls);
            return obj;
        }
    }
#endif

    // No shortcuts available.
    if (allocWithZone) return [cls allocWithZone:nil];
    return [cls alloc];
}

對于OC提供的方法罪塔,除了上面幾種投蝉,比如說[NSMutableArray array],通過這些方法獲取到的對象并不對其進(jìn)行持有征堪,內(nèi)部會將生成的對象放入到自動釋放池上

// 取得非自己生成而且不持有的對象
id obj = [NSMutableArray array];

// 進(jìn)行retain之后瘩缆,obj持有了對象
[obj retain];

再比如如果我們定義一個方法:

- (id)object {
    id obj = [[NSObject alloc] init];
    
    // 加入自動釋放池,pool銷毀的池銷毀的同事對obj進(jìn)行release一次
    [obj autorelease]; 
        
    return obj;
}
image.png

無法釋放非自己持有的對象

就像上面的 id obj1 = [obj1 object]佃蚜,obj并沒有持有對象咳榜,如果這時候我們主動調(diào)用[obj1 release]就會發(fā)生崩潰。

還有一種情況就是已經(jīng)被釋放的對象再對其進(jìn)行release操作的時候也會發(fā)生崩潰

id obj = [[NSObject alloc] init];
[obj release];

[obj release]; // crash

ARC中常見的所有權(quán)關(guān)鍵字

  • assign對應(yīng)關(guān)鍵字__unsafe_unretained, 顧名思義爽锥,就是指向的對象被釋放的時候涌韩,仍然指向之前的地址,容易引起野指針氯夷。

  • copy對應(yīng)關(guān)鍵字__strong,只不過在賦值的時候臣樱,調(diào)用copy方法。

  • retain對應(yīng)__strong

  • strong對應(yīng)__strong

    __strong修飾符是id類型和對象類型默認(rèn)的所有權(quán)修飾符腮考。也就是說雇毫,以下源代碼?中的id變量,實際上被附加了所有權(quán)修飾詞:

    id obj = [[NSObject alloc] init];
    
  • weak 對應(yīng) __weak

    weak是用來替代unsafe_unretained踩蔚,weak修飾符的變量(即弱引用)不持有對象棚放,所以在超出其作用域時,對象就會釋放馅闽,所以因為強(qiáng)引用而造成的循環(huán)引用飘蚯,將其中的成員變量改為弱引用馍迄,就不會發(fā)生相同情況。

    在持有某若引用時局骤,若該對象被廢棄攀圈,則此弱引用將自動失效且處于nil被賦值狀態(tài)(空弱引用)。

  • unsafe_unretained 對應(yīng) __unsafe_unretained

unsafe unretained與weak修飾符一樣不會增加引用計數(shù)峦甩,自己生成的對象不能繼續(xù)為自己所有赘来,所以會立即釋放。

iOS4以及OS X Snow Leopard的應(yīng)用程序中凯傲,必須使用unsafe unretained修飾符來替代weak修飾符犬辰。賦值給附有__unsafe unretained修飾符變量的對象在通過該變量使用時,如果沒有確保其存在冰单,那么應(yīng)用就會崩潰幌缝。

id __unsafe_unretained obj1 = nil;
{
    id __strong obj0 = [NSObject new];
    obj1 = obj0;
    NSLog(@"A: %@", obj1);
}
NSLog("%@", [obj1 description];);

如果像上面那樣,程序就會崩潰球凰,因為obj0被銷毀之后狮腿,obj1并不會自動置為nil。


__bridge

id obj = [[NSObject alloc] init];
 
void *p = (__bridge void *)obj;
 
id o = (__bridge id)p;

將Objective-C的對象類型用 __bridge 轉(zhuǎn)換為 void* 類型和使用 __unsafe_unretained 關(guān)鍵字修飾的變量是一樣的

__bridge轉(zhuǎn)換中還有另外兩種轉(zhuǎn)換呕诉,分別是" __bridge_retained轉(zhuǎn)換"和" __bridge_transfer轉(zhuǎn)換"

  • __bridge_retained轉(zhuǎn)換可使要轉(zhuǎn)換賦值的變量也持有所賦值的對象缘厢。
// MRC
void *p = 0;
{
    id obj = [NSObject new]; // retainCount = 1
    p = (__bridge_retained void *)obj; // retainCount = 2
}
NSLog(@"class=%@", [(__bridge id)p class]);
// log:class=NSObject
  • __bridge_transfer轉(zhuǎn)換提供與次相反的動作,被轉(zhuǎn)換的變量所持有的對象在該變量被賦值給轉(zhuǎn)換目標(biāo)變量后隨之釋放甩挫。
id p = (__bridge_transfer id)p;

等效于:

// MRC
id obj = (id)p;
[obj retain];
[(id)p release];

__bridge_retainedretain類似贴硫,__bridge_transferrelease相似。 在給id obj賦值時retain即相當(dāng)于__strong修飾符的變量伊者。

如果使用以上兩種轉(zhuǎn)換英遭,那么不是用id類型或者對象型變量也可以生成、持有以及釋放對象亦渗。雖然可以這樣做挖诸,但是ARC中并不推薦。

void *p = (__bridge_retained void *)[NSObject new];
NSLog(@"class = %@", [(__bridge id)p class]);
(void)(__bridge_transfer id)p;

和下面代碼等效

// MRC
id p = NSObject new];
NSLog(@"class = %@", [p class]);
[p release];

Objective-C對象與Core Foundation對象

Core Foundation對象主要使用在C語言編寫的Core Foundation框架中法精,并是用引用計數(shù)的對象多律。在ARC無效時,Core Foundation框架中的retain/release分別是CFRetain/CFRelease搂蜓。

因為Core Foundation對象與OC對象沒有區(qū)別狼荞,所以在MRC時,只用簡單的C語言的轉(zhuǎn)換也能實現(xiàn)互換帮碰。另外這種轉(zhuǎn)換不需要使用額外的CPU資源相味,因此也被稱為"Toll-Free Bridge"

以下函數(shù)可用于OC對象和Core Foundation對象之間的相互變換,即Toll-Free Bridge轉(zhuǎn)換:

CFTypeRef CFBridgingRetain(id x) {
    return (__bridge_retained CFTypeRef) x;
}

id CFBridgingRelease(CFTypeRef x) {
    return (__bridge_transfer id)x;
}
CFMutableArrayRef cfObj = NULL;
        {
            NSMutableArray *obj = [[NSMutableArray alloc] init];
            cfObj = CFBridgingRetain(obj);
            CFShow(cfObj);
            NSLog(@"retainCount = %ld", CFGetRetainCount(cfObj));
        }
        NSLog(@"after retainCount = %ld", CFGetRetainCount(cfObj));
        CFRelease(cfObj);

效果如下

image.png

還可以通過__bridge_retained來替代CFBridgingRetain

CFMutableArrayRef cfObject = (__bridge_retained CFMutableArrayRef)obj;

反過來

CFMutableArrayRef cfObj = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
NSLog(@"retainCount = %ld", CFGetRetainCount(cfObj));

id obj = CFBridgingRelease(cfObj);
// CFRelease(cfObj);
NSLog(@"after retainCount = %ld", CFGetRetainCount((__bridge CFTypeRef)(obj)));

打印出來:


image.png

和書上的結(jié)果好像不一樣殉挽,如果加上CFRelsease就正常了丰涉,這個點沒有搞清楚:

image.png

如果我們直接用__bridge_transfer進(jìn)行轉(zhuǎn)換拓巧,結(jié)果幾就過就正常了:

CFMutableArrayRef cfObj = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
NSLog(@"retainCount = %ld", CFGetRetainCount(cfObj));

//NSMutableArray *obj = CFBridgingRelease(cfObj);
            
NSMutableArray *obj = (__bridge_transfer NSMutableArray *)(cfObj);
//CFRelease(cfObj);
NSLog(@"after retainCount = %ld", CFGetRetainCount((__bridge CFTypeRef)(obj)));
image.png

ARC運(yùn)行時的優(yōu)化

ARC不只是在編譯時由編譯器進(jìn)行內(nèi)存管理,實際上在此基礎(chǔ)還借助了OC運(yùn)行時庫昔搂。也就是說玲销,ARC由以下工具输拇、庫實現(xiàn):

  • clang(LLVM編譯器)3.0以上
  • objc4 Objective-C運(yùn)行時庫493.9以上
__strong修飾符

賦值給__strong修飾的變量:

{
    id __strong obj = [[NSObject alloc] init];
}

可以看作成:

id obj = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(obj, @selector(init));
objc_release(obj);

// 調(diào)用2次objc_msgSend方法摘符,變量作用域結(jié)束時,objc_release釋放對象策吠。
// 由此看出編譯器會自動插入release操作逛裤。

--
使用alloc/new/copy/mutableCopy以外的方法:

{
    id __strong obj = [NSMutableArray array];
}

可以看作:

id obj = objc_msgSend(NSMutableArray, @selector(array));
objc_retainAutoreleaseReturnValue(obj);
objc_release(obj);

這里和上面區(qū)別主要是objc_retainAutoreleaseReturnValue,該函數(shù)主要用于優(yōu)化程序運(yùn)行猴抹,objc_retainAutoreleaseReturnValue的入?yún)⑹欠祷?code>注冊在autoreleasepool中的對象的方法/函數(shù)的返回值带族。編譯器會在alloc/new/copy/mutableCopy以外的方法調(diào)用外部插入。

上面所說的功能實現(xiàn)的時候是需要objc_retainAutoreleaseReturnValueobjc_autoreleaseReturnValue配合完成蟀给,任何不在alloc/new/copy/mutableCopy組中的方法必須調(diào)objc_autoreleaseReturnValue蝙砌。 例如,NSMutableArray類方法“array”調(diào)用此函數(shù)跋理。

+ (id)array {
    return [[NSMutableArray alloc] init];
}
/* pseudo code by the compiler */ 
+ (id) array {
    id obj = objc_msgSend(NSMutableArray, @selector(alloc));    objc_msgSend(obj, @selector(init));
    return objc_autoreleaseReturnValue(obj);
}

任何返回添加到自動釋放池的對象的方法都將調(diào)用objc_autoreleaseReturnValue函數(shù)择克,如上例所示。 它將一個對象添加到自動釋放池并返回前普。 但是實際上objc_autoreleaseReturnValue不會一直注冊到自動釋放池肚邢。

objc_autoreleaseReturnValue檢查調(diào)用者的可執(zhí)行代碼,如果代碼在調(diào)用此方法后調(diào)用objc_retainAutoreleasedReturnValue函數(shù)拭卿,它將跳過注冊到自動釋放池骡湖,并將對象返回給調(diào)用者。 即使objc_autoreleaseReturnValue沒有將對象注冊到自動釋放池峻厚,objc_retainAutoreleasedReturnValue函數(shù)也可以正確地獲得這樣的對象响蕴。 通過objc_autoreleaseReturnValueobjc_retainAutoreleasedReturnValue的合作,對象繞過被添加到自動釋放池惠桃。

一般來說:檢驗了主調(diào)方在返回值之后是否緊接著調(diào)用了objc_retainAutoreleasedReturnValue浦夷,如果是,就知道了外部是ARC環(huán)境刽射,反之就走沒被優(yōu)化的老邏輯军拟。

image.png

__weak修飾符

  • 當(dāng)引用對象被丟棄時,__weak修飾的變量會賦值為nil誓禁。
  • 通過__weak限定變量訪問對象時懈息,該對象將添加到自動釋放池。
{
    id __weak obj1 = obj; // 假色obj誒__strong修飾且對象被賦值
}
/* pseudo code by the compiler */ 
id obj1;
objc_initWeak(&obj1, obj); 
objc_destroyWeak(&obj1);

通過objc_initWeak初始化__weak修飾的變量摹恰,在變量作用域結(jié)束時通過objc_destroyWeak釋放該變量辫继。

objc4源碼中objc_initWeakobjc_destroyWeak的具體實現(xiàn)

id objc_initWeak(id *location, id newObj)
{
    if (!newObj) {
        *location = nil;
        return nil;
    }

    return storeWeak<false/*old*/, true/*new*/, true/*crash*/>
        (location, (objc_object*)newObj);
}

void objc_destroyWeak(id *location)
{
    (void)storeWeak<true/*old*/, false/*new*/, false/*crash*/>
        (location, nil);
}

所以怒见,本質(zhì)上都是調(diào)用了storeWeak函數(shù),storeWeak函數(shù)把第二參數(shù)的賦值對象的地址作為鍵值姑宽,將第一個參數(shù)的附有__weak修飾符的變量的地址注冊到weak表中遣耍。如果第二個參數(shù)為0/nil,則把變量的地址從weak表中刪炮车。

這個函數(shù)總結(jié)起來主要做了以下事情:

  • 獲取存儲weak對象的map舵变,這個map的key是對象的地址,value是weak引用的地址
  • 當(dāng)對象被釋放的時候瘦穆,根據(jù)對象的地址可以找到對應(yīng)的weak引用的地址纪隙,將其置為nil即可

weak表與引用計數(shù)表都是采用散列表實現(xiàn)。另外扛或,由于一哥對象可以同時賦值給多個__waek對象修飾符的變量中绵咱,對于一個鍵值,可以注冊多個變量的地址熙兔。

釋放對象的時候悲伶,一般經(jīng)歷下面幾個操作:

  1. objc_release
  2. 因為引用計數(shù)為0所以執(zhí)行dealloc
  3. _objc_rootDealloc
  4. object_dispose
  5. objc_destructInstance
  6. objc_clear_deallocating

對象被廢棄時最后調(diào)用的objc_ckear_deallocating函數(shù)動作如下:

  1. 從weak表中獲取廢棄對象的地址為鍵值的記錄
  2. 將包含在記錄中的所有附有__weak修飾符變量的地址,賦值為nil
  3. 從weak表傷處該記錄
  4. 從應(yīng)用計數(shù)表中刪除廢棄對象的地址為鍵值的記錄

通過上面的步驟可以看出住涉,如果大量的是用__weak修飾符的變量麸锉,會對cpu資源造成相應(yīng)的消耗,一般只有在需要避免循環(huán)引用的時候是用__weak修飾符秆吵。

image.png

如果我們像上圖那樣淮椰,自己生成對象并復(fù)制給__weak變量,自己不能持有該對象纳寂,對象會馬上被回收主穗,引起編譯器警告

編譯器處理后代碼:

/* pseudo code by the compiler 
    雖然自己生成并持有對象,但是編譯器判斷其沒有持有責(zé)毙芜,因此被釋放
*/
id obj;
id tmp = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(tmp, @selector(init)); 
objc_initWeak(&obj, tmp);
objc_release(tmp);
objc_destroyWeak(&obj);

然后再來測試一下:使用__weak修飾符的變量是否會將對象注冊到autoreleasepool忽媒。

{
    id __weak obj1 = obj;
    NSLog("%@", obj1);
}
/* 編譯器的模擬代碼 */
id obj1;
objc_initWeak(&obj1, obj);
id tmp = objc_loadWeakRetained(&obj1);
objc_autorelease(tmp);
NSLog(@"%@", tmp);
objc_destroyWeak(&obj1);

與被賦值相比,在使用附有__weak修飾變量的情況下腋粥,增加了對objc_loadWeakRetained函數(shù)和objc_autorelease函數(shù)的調(diào)用晦雨。

  • objc_loadWeakRetained函數(shù)取出附有__weak修飾符變量所引用的對象并ratain
  • objc_autorelease函數(shù)將對象注冊到autoreleasepool中

由于附有__weak修飾符變量所引用的對象能被注冊到autoreleasepool中,所以在@autoreleasepool塊結(jié)束前都能保證對象不被釋放隘冲。但是闹瞧,如果大流量地是用__weak變量會導(dǎo)致autoreleasepool的對象也會大量地添加,因此在使用__weak變量最好先暫時賦值給__strong變量再是用后者展辞。

這樣就能解釋我們平時用到的weak-strong-dance的原理了奥邮。以AFN的源碼為例子:

__weak __typeof(self)weakSelf = self;
    AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
        __strong __typeof(weakSelf)strongSelf = weakSelf;

        strongSelf.networkReachabilityStatus = status;
        if (strongSelf.networkReachabilityStatusBlock) {
            strongSelf.networkReachabilityStatusBlock(status);
        }

    }

上面在閉包中利用把weakSelf賦值給strongSelf,保證在callback閉包執(zhí)行的過程中,self不會被釋放洽腺。

題外話

  • 1脚粟、內(nèi)斂函數(shù)

內(nèi)聯(lián)函數(shù)是指用inline關(guān)鍵字修飾的函數(shù)。內(nèi)聯(lián)函數(shù)不是在調(diào)用時發(fā)生控制轉(zhuǎn)移蘸朋,而是在編譯時將函數(shù)體嵌入在每一個調(diào)用處核无。編譯時,類似宏替換藕坯,使用函數(shù)體替換調(diào)用處的函數(shù)名团南。參考資料

參考文章:
黑幕背后的Autorelease
自動釋放池的前世今生 ---- 深入解析 Autoreleasepool
深入理解Objective C的ARC機(jī)制

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市堕担,隨后出現(xiàn)的幾起案子已慢,更是在濱河造成了極大的恐慌曲聂,老刑警劉巖霹购,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泉手,死亡現(xiàn)場離奇詭異幔嗦,居然都是意外死亡锻全,警方通過查閱死者的電腦和手機(jī)倒庵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進(jìn)店門棺滞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來聊训,“玉大人窒篱,你說我怎么就攤上這事咆霜∏蠲啵” “怎么了轿塔?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長仲墨。 經(jīng)常有香客問我勾缭,道長,這世上最難降的妖魔是什么目养? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任俩由,我火速辦了婚禮,結(jié)果婚禮上癌蚁,老公的妹妹穿的比我還像新娘幻梯。我一直安慰自己,他們只是感情好努释,可當(dāng)我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布碘梢。 她就那樣靜靜地躺著,像睡著了一般伐蒂。 火紅的嫁衣襯著肌膚如雪煞躬。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天饿自,我揣著相機(jī)與錄音汰翠,去河邊找鬼龄坪。 笑死,一個胖子當(dāng)著我的面吹牛复唤,可吹牛的內(nèi)容都是我干的健田。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼佛纫,長吁一口氣:“原來是場噩夢啊……” “哼妓局!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起呈宇,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤好爬,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后甥啄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體存炮,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年蜈漓,在試婚紗的時候發(fā)現(xiàn)自己被綠了穆桂。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡融虽,死狀恐怖享完,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情有额,我是刑警寧澤般又,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站巍佑,受9級特大地震影響茴迁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜句狼,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一笋熬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧腻菇,春花似錦胳螟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至丘薛,卻和暖如春嘉竟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工舍扰, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留倦蚪,地道東北人。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓边苹,卻偏偏與公主長得像陵且,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子个束,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容

  • 1.1 什么是自動引用計數(shù) 概念:在 LLVM 編譯器中設(shè)置 ARC(Automaitc Reference Co...
    __silhouette閱讀 5,084評論 1 17
  • 自動引用計數(shù) 自動引用計數(shù):指內(nèi)存管理中對引用采取自動計數(shù)的技術(shù)茬底。 內(nèi)存管理/引用計數(shù) 持有對象引起引用計數(shù)加...
    南京小伙閱讀 1,300評論 2 3
  • 一沪悲、內(nèi)存管理的思考方式下文會常用到的術(shù)語解釋生成對象:創(chuàng)建對象持有對象:引用計數(shù)+1釋放對象:引用計數(shù)-1廢棄對象...
    iOSUI拖拽工程師閱讀 1,522評論 0 3
  • 前言:本篇內(nèi)容假設(shè)您已經(jīng)對內(nèi)存管理有了基礎(chǔ)的理解。如retain阱表、release殿如、autorelease、auto...
    greatboygirl閱讀 660評論 0 3
  • 文/歲月靜好 惜別福羊捶枢, 喜迎金猴握截。 桃花謝了荷立, 楓葉紅了梅香烂叔。 太匆匆! 憶往昔固歪, 漫天雪花飛揚(yáng)蒜鸡, 鞭炮聲聲...
    歲月靜好diligent閱讀 221評論 4 3