Objective-C中的內(nèi)存管理

iOS開發(fā)中, 之前一直使用swift, 因此對于Objective-C的內(nèi)存管理機制長期處于混亂的一知半解狀態(tài). 今天終于看到一篇講得透徹的博客[Objective-C內(nèi)存管理教程和原理剖析](http://blog.jobbole.com/66197/), 感謝作者.

本文只是個人的一個學(xué)習(xí)摘要, 更詳細內(nèi)容請參考原文.

ARC黃金法則:

>The basic rule to apply is:

***Everything that increases the reference counter with alloc, [mutable]copy[WithZone:] or retain is in charge of the corresponding [auto]release***.

## 基本的內(nèi)存分配

OC的對象是在堆里邊生成, 需要一個指針指向它.

```

ClassA *obj1 = [[ClassA alloc] init];

```

使用完之后不會自動銷毀, 需執(zhí)行dealloc來銷毀, 否則會出現(xiàn)內(nèi)存泄露.

```

[obj1 dealloc];

```

那么看如下代碼:

```

ClassA *obj1 = [[ClassA alloc] init];

ClassA *obj2 = obj1;

[obj1 hello];

[obj1 dealloc];

// obj1, obj2都是指針, 指向同一對象. 而[obj1 dealloc]已經(jīng)銷毀了該對象. 因此下邊的代碼無法執(zhí)行, obj2是無效指針.

[obj2 hello];

[obj2 dealloc];

```

## 引用計數(shù)

為了避免出現(xiàn)上邊的無效指針,? OC采用引用計數(shù)的方式. 引用計數(shù)加1的有:alloc, retain, strong, 減1的有release. 當(dāng)對象的引用計數(shù)為0的時候, 會自動調(diào)用dealloc.

```

ClassA *obj1 = [[ClassA alloc] init]; // 計數(shù)為1

[obj1 release]; // 計數(shù)為0, 自動dealloc

ClassA *obj1 = [[ClassA alloc] init]; // 計數(shù)為1

ClassA *obj2 = obj1; // 計數(shù)為1, 指針賦值不會增加引用計數(shù)

[obj1 hello];

[obj1 release]; // 計數(shù)為0, 自動dealloc

// 因?qū)ο笠驯籨ealloc, 故以下代碼不會執(zhí)行, obj2仍然是無效指針.

[obj2 hello];

[obj2 release];

```

那么如何解決obj2的無效指針問題呢? 通過retain使得引用計數(shù)加1.

```

ClassA *obj1 = [[ClassA alloc] init]; // 計數(shù)為1

ClassA *obj2 = obj1; // 計數(shù)為1

[obj2 retain]; // 計數(shù)為2

[obj1 hello];

[obj1 release]; // 計數(shù)為1

[obj2 hello];

[obj2 release]; // 計數(shù)為0, 自動dealloc

```

所以, 引用計數(shù)的關(guān)鍵在于當(dāng)對象的引用計數(shù)為0時, 會自動調(diào)用dealloc銷毀該對象. 指針賦值時, retain count不會自動增加, 需要手動retain.

另外, release一個對象之后, 應(yīng)立即將指針清空(release一個空指針是合法的). 如:

```

ClassA *obj1 = [[ClassA alloc] init];

[obj1 release];

obj1 = nil;

```

## Autorelease

自動釋放池其實是NSAutoreleasePool, 可以自動釋放對象.

```

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

```

NSAutoreleasePool內(nèi)部包含一個NSMutableArray, 用于保存聲明為autorelease的所有對象.

下邊看一下Apple的例子:

首先不用autorelease,

```

- (NSString *)fullName {

NSString *string = [[NSString alloc] initWithFormat:@"%@ %@", self.firstName, self.lastName];

return string;

}

```

則, 該string不能找到合適的時機釋放, 因此會出現(xiàn)內(nèi)存泄露.

那么, 采用autorelease之后,

```

- (NSString *)fullName {

NSString *string = [[[NSString alloc] initWithFormat:@"%@ %@", self.firstName, self.lastName] autorelease];

return string;

}

```

雖然, string不會立即釋放, 但autorelease會在其release的時機將其釋放.

或者采用更直接簡便的方式, 這種方式?jīng)]有alloc, 所以也不要求release.

```

- (NSString *)fullName {

NSString *string = [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];

return string;

}

```

其實, 此方式也是通過alloc+autorelease的方式來實現(xiàn)的, 只是對使用者而言, 省掉了alloc+autorelease的步驟.

NSAutoreleasePool自身在銷毀的時候, 會遍歷并試圖release其中的所有autorelease對象. 如果該對象的引用計數(shù)為1, 則將其引用計數(shù)減1, 銷毀該對象; 如果該對象的引用計數(shù)大于1, 則autorelease之后其引用計數(shù)仍大于0, 對象未銷毀, 出現(xiàn)內(nèi)存泄露.

如在iOS工程的main.m文件中

```

int main(int argc, char * argv[]) {

@autoreleasepool {

return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));

}

}

```

其實可以自行使用NSAutoreleasePool,

```

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

for (int i=0;i<100;i++) {

for (int j=0;j<10000;j++) {

// 產(chǎn)生autorelease對象

[NSString stringWithFromat:@"1234567890"];

}

}

[pool release];

return 0;

```

可以看出, 所有autorelease對象都只能在NSAutoreleasePool執(zhí)行release的時候銷毀, 顯然不能很好地利用內(nèi)存. 那么可以使用內(nèi)嵌的NSAutoreleasePool, 代碼優(yōu)化如下:

```

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

for (int i=0;i<100;i++) {

NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];

for (int j=0;j<10000;j++) {

// 產(chǎn)生autorelease對象

[NSString stringWithFromat:@"1234567890"];

}

[loopPool release];

}

[pool release];

return 0;

```

這樣, 就可以做到及時地釋放內(nèi)存.

所以, 實例化一個對象可以有兩種方法:

1. 采用alloc + release的方法

```

Dog *dog = [[Dog alloc] init];

// 代碼

[dog release]; // alloc 和 release 必須一一對應(yīng).

```

2. 采用autorelease的方法

```

// 這種方式把dog對象加到autorelease pool中, 就不需要手動release了.

+ (id)dog {

return [[[Dog alloc] init] autorelease];

}

```

所以, NSAutoreleasePool的關(guān)鍵在于, 放置到其中的autorelease對象, 會在該pool release的時候自動銷毀(絕大多數(shù)情況下, 都是正常的引用計數(shù)為1的autorelease對象). 因此對象本身就沒必要調(diào)用release方法. 同時NSAutoreleasePool的release時機很重要. 因為autorelease pool不會立即釋放, 當(dāng)它到了最近的pool release的時候才會自動檢測retainCount是否為0, 一旦為0則釋放pool. 當(dāng)pool本身銷毀的時候, 其中的對象才會執(zhí)行release操作, 否則將一直占用內(nèi)存空間.

所以, 不要濫用autorelease, 如對象的生命周期很清晰, 則結(jié)束使用后立即release. 過多等待autorelease對象浪費內(nèi)存.

## property中的關(guān)鍵字

***@property中的關(guān)鍵字表示屬性如何存儲, 其實全都是用于設(shè)置getter/setter的操作特性***, 如果我們將getter/setter展開來看的話就會很明白.

### assign

assign相當(dāng)于指針賦值, 不對引用計數(shù)進行操作, 如原對象不用了, 一定要將其設(shè)置為nil. 一般基本變量用該屬性聲明, 如int, BOOL.

即: 調(diào)用setter方法時直接賦值, 不進行retain操作. 不改變引用計數(shù).

***assign與weak的區(qū)別在于:***

>當(dāng)指針?biāo)赶驅(qū)ο髍elease之后, weak會賦nil給該指針, 而assign不會賦nil給指針. 所以使用assign的時候, 一旦指針?biāo)赶驅(qū)ο髍elease之后, 再給該對象發(fā)送消息(調(diào)用方法), 程序即會crash.

weak用于OC對象的弱引用, assign用于C原始類型.

### retain

retain其實是指針拷貝(地址相同), 會增加對象的引用計數(shù)五芝,而OC中的基本數(shù)據(jù)類型沒有引用計數(shù)粱快。

如: 把對象添加到數(shù)組中[array addObject:obj];,該對象obj的引用計數(shù)retainCount將加1. 如下圖

![內(nèi)存管理retain](http://img.blog.csdn.net/20150628091306890)

使用retain, 調(diào)用setter方法時, 先release舊值, 對賦予的新值進行引用計數(shù)+1. 二者的內(nèi)存地址一樣.

看下邊的例子:

```

// Person.h

@interface Person: NSObject {

Dog *_dog;

}

@property (retain) Dog *dog;

@end

```

```

// Person.m

@implementation Person

@synthesize dog = _dog;

- (void) dealloc {

self.dog = nil; // 其實調(diào)用[self setDog:nil];方法

[super dealloc];

}

@end

```

參考之前的一篇文章[Objective-C中類的成員變量與屬性](http://blog.csdn.net/icetime17/article/details/45537975), 可知@property與@synthesize的關(guān)系, 總之, 這里編譯器會識別@synthesize, 并自動為dog屬性添加getter/setter方法.

編譯器對 @property (retain) Dog *dog; 展開為:

```

- (Dog *)dog;

- (void)setDog:(Dog *)aDog;

```

編譯器對 @synthesize dog = _dog; 展開為:

```

- (Dog *)dog {

return _dog;

}

- (void)setDog:(Dog *)aDog {

if (_dog != aDog) {

[_dog release]; // 即使_dog的retainCount已為0, 對其做release也不會出錯.

_dog = [aDog retain];

}

}

```

getter/setter方法是被編譯器隱藏的, 如果不使用@synthesize dog = _dog;的話, 必須自己編寫這兩個方法.

### copy

不同于retain的指針拷貝, copy都是內(nèi)容拷貝. 即復(fù)制一個對象變成新的對象(新的內(nèi)存地址), 新對象的引用計數(shù)為1, 原對象的引用計數(shù)不變. 所以, copy得到的均為一個獨立的對象, 跟原對象沒有關(guān)系.

一般來說, ***block都是使用copy關(guān)鍵字***. 如下邊的SelectedCity的使用, 在這里只是簡單地截取部分代碼, 不做太具體的解釋. 需要詳細了解block的同學(xué), 可以參考[轉(zhuǎn): 深入理解Objective-C的Block](http://blog.csdn.net/icetime17/article/details/46649423).

在CityListViewController中

```

// CityListViewController.h

typedef void(^SelectedCity)(NSString *);

@interface CityListViewController: UIViewController

@property (nonatomic, copy) SelectedCity selectedCity;

@end

// CityListViewController.m

if (_selectedCity) {

_selectedCity(cell.textLabel.text);

}

```

在MainViewController中:

```

// MainViewController.h

typedef void(^SelectedCity)(NSString *);

@interface MainViewController: UIVieController

@property (nonatomic, copy) SelectedCity selectedCity;

@end

// MainViewController.m

- (void)viewDidLoad {

__weak MainViewController *weakVC = self;

_selectedCity = ^(NSString *city) {

weakVC.cityLabel.text = city;

weakVC.vTracks.selectedCity = city; // vTracks中有selectedCity屬性

[weakVC.vTracks invokeRefresh];

};

}

- (IBAction)cityListClicked:(UIButton *sender) {

CityListViewController *cityListVC = [CityListViewController alloc] init];

cityListVC.selectedCity = _selectedCity;

[self.navigationController pushViewController:cityListVC animated:YES];

}

```

編譯器對 @property (copy) NSString *str; 展開為

```

- (NSString *)str {

return _str;

}

- (void)setStr:(NSString *)newStr {

if (_str != newStr) {

[_str release];

_str = [newStr copy];

}

}

```

copy其實有兩種:

1. copy得到的是不可變類型, 如NSString, NSArray, NSDictionary, NSData, NSSet.

2. mutableCopy得到的是mutable類型. 如NSMutableString, NSMutableArray, NSMutableDictionary, NSMutableData, NSMutableSet.

***copy操作必須遵循NSCopying和NSMutableCopying協(xié)議, 實現(xiàn)其中的copyWithZone:和mutableCopyWithZone:方法, 即告訴編譯器如何做到copy操作***.

```

- (id)copyWithZone:(NSZone *)zone {

Dog *dog = [[[[self class] allocWithZone:zone] init] autorelease];

dog.name = self.name;

dog.year = self.year;

return dog;

}

```

### deep copy

上邊的copy默認都是淺拷貝, 如對于NSArray而言, 淺拷貝只是copy一份NSArray, 該NSArray中的每一個元素仍然指向原NSArray中指向的對象.? 如下圖:

![內(nèi)存管理copy](http://img.blog.csdn.net/20150628091451099)

而deep copy則將NSArray中元素指向的對象也做一份拷貝, 一般用于NSArray, NSDictionary. 如下圖:

![內(nèi)存管理deepCopy](http://img.blog.csdn.net/20150628091542228)

deep copy有兩種實現(xiàn)方式:

***1. 使用copyItems***

copyItems

```

- (id)initWithArray:(NSArray *)array copyItems:(BOOL)flag;

- (id)initWithDictionary:(NSDictionary *)otherDictionary copyItems:(BOOL)flag;

```

使用如下:

```

NSMutableArray *_carList = [[NSMutableArray alloc] init];

// 向_carList中填充內(nèi)容

NSMutableArray *carList1 = [[NSMutableArray alloc] initWithArray:_carList];

// 淺拷貝, 同樣會改變原_carList中的內(nèi)容

[[carList1 objectAtIndex:0] setName:@"淺拷貝內(nèi)容"];

NSMutableArray *carList2 = [[NSMutableArray alloc] initWithArray:_carList copyItems:YES];

// deep copy, 則不會改變原_carList中的內(nèi)容

[[carList2 objectAtIndex:0] setName:@"deep copy內(nèi)容"];

```

***2. 使用歸檔NSKeyedArchiever***

歸檔是將整個數(shù)組以二進制形式存到NSData中, 需要的時候就將其讀取出來再轉(zhuǎn)換成原來數(shù)組的形式.

```

// 將NSArray的內(nèi)容保存到NSData中

NSData *data = [NSKeyedArchiver archivedDataWithRootObject:_carList];

// 將二進制對象data還原成NSArray

NSMutableArray *carList3 = NSKeyedArchiver unarchiveObjectWithData:data];

```

歸檔需要繼承NSCoding協(xié)議, 實現(xiàn)encodeWithCoder:和initWithCoder:兩個方法.

```

// 存檔方法

- (void)encodeWithCoder:(NSCoder *)aCoder {

[aCoder encodeObject:self.name forKey:@"name"];

[aCoder encodeObject:self.year forKey:@"year"];

}

// 解檔方法

- (id)initWithCoder:(NSCoder *)aDecoder {

self = [super init];

if (self) {

self.name = [aDecoder decodeObjectForKey:@"name"];

self.year = [aDecoder decodeIntForKey:@"year"];

}

return self;

}

```

### strong

strong是強引用, 持有對象, 對象的引用計數(shù)+1, 如string1和string2都指向一個字符串, 則string1=nil, 而string2不變.

所有strong修飾符的變量在超出其變量作用域時, 釋放其被賦予的對象. 即持有強引用的變量在超出其作用域時被放棄, 隨著強引用的失效, 引用的對象會隨之釋放.

strong變量執(zhí)行ARC計數(shù), 不會自動釋放. 其死亡直接決定了所指向?qū)ο蟮乃劳?

為了確保使用中的實例不會被銷毀,ARC 會跟蹤和計算每一個實例正在被多少屬性吹害,常量和變量所引用。哪怕實例的引用數(shù)為1,ARC都不會銷毀這個實例。

為了使之成為可能采幌,無論你將實例賦值給屬性,常量或者是變量震桶,屬性休傍,常量或者變量,都會對此實例創(chuàng)建強引用蹲姐。之所以稱之為強引用磨取,是因為它會將實例牢牢的保持住人柿,只要強引用還在,實例是不允許被銷毀的忙厌。

實際上, strong和retain的意思相同, 推薦使用strong代替retain.

***id類型和對象類型的所有權(quán)修飾符默認為strong, 會影響對象回收***

### weak

使用strong容易引起循環(huán)引用的問題. 為了防止循環(huán)強引用凫岖,可采用弱引用和無主引用。這兩種允許循環(huán)引用中的一個實例引用另外一個實例而不保持強引用逢净,這樣實例能夠相互引用而不產(chǎn)生循環(huán)強引用哥放。

弱引用? :對于生命周期中會變?yōu)閚il的實例采用。

無主引用:對于初始化賦值后再也不會變?yōu)閚il的實例采用汹胃。

weak是弱引用, 不持有對象, 在超出其變量作用域時, 對象即被釋放. 在持有某對象的弱引用時, 若該對象被釋放, 則此弱引用將自動失效且等于nil.

對象的計數(shù)不變. 如string1和string2都指向一個字符串, 則string1=nil, 那么string2也會變?yōu)閚il.

因其沒有retain內(nèi)存地址, 若其指向的地址對象一旦釋放, 則該指針會指向nil.

ARC空閑時釋放, 對象釋放時自動將指針置NULL. 不決定對象的存亡, 即使一個對象被持有無數(shù)個弱引用, 只要沒有強引用指向它, 則最后還是會清除

如兩個對象互相為對方的成員變量, 則一定不能同時retain, 否則dealloc函數(shù)形成死鎖, 兩個對象都無法釋放. weak可以用于防止野指針和死鎖, 避免循環(huán)引用.

ARC機制中婶芭,為什么UI對象用weak东臀,代理用weak着饥?比如我們往view里加一個button,相當(dāng)于在subviews這個數(shù)組里加一個button惰赋,這個數(shù)組空間里會有一塊內(nèi)存指向button宰掉,是強指針,只要控制器還在赁濒,button就在轨奄,所以當(dāng)創(chuàng)建button時用? weak,防止內(nèi)存泄漏拒炎。代理如果是強指針的話挪拟,它指向控制器,那么所有東西都不能relese了击你,前面道理同UI控件玉组。

***weak不會影響對象回收, 一般UI對象和delegate用weak***

### __weak

__weak 聲明了可以自動nil化的弱引用.

注意: block被copy時, 會對block中用到的對象產(chǎn)生強引用(引用計數(shù)+1). 如果block中又引用了對象的其他成員變量, 就會對該變量本身產(chǎn)生強引用, 則變量本身和它自己的block屬性就形成了循環(huán)引用. 即使用self之類的有可能導(dǎo)致retain cycle, 所以一般用__weak的方式.

請看下邊的城市列表例子.

在CityListVC中, 通過block將city的值傳遞給MainVC.

在CityListVC.h中: 定義block塊對象

```

typedef void(^SelectedCity)(NSString *);

@property(copy,nonatomic) SelectedCity selectCity;

CityListVC.m中:

if (_selectCity) {

_selectCity(cell.textLabel.text); // 這里要通過block進行View之間的數(shù)據(jù)傳遞.

}

```

MainVC.h中:

```

typedef void(^SelectedCity)(NSString *);

@property(copy,nonatomic) SelectedCity selectCity;

```

MainVC.m中:

```

self.vTracks.selectedCity = @"城市";

__weak MainViewController *weakVC = self;

_selectCity = ^(NSString *city){

weakVC.cityLabel.text = ([city isEqualToString:@"全國"]) ? @"城市" : city;

weakVC.vTracks.selectedCity = ([city isEqualToString:@"城市"] | [city isEqualToString:@"全國"]) ? nil : city;

[weakVC.vTracks invokeRefresh];

};

```

在block中, 使用__weak的方式聲明了一個weakVC, 即對自身對象的弱引用. 即block對象不對self對象進行retain, 弱引用的方式可以避免出現(xiàn)循環(huán)引用. 如果是non-ARC, 則使用__block替換__weak, 即在block中引入一個新的結(jié)構(gòu)體成員變量指向這個__block變量, __block typeof(self) weakSelf = self.

### static

static, 全局變量.

1. 函數(shù)體內(nèi)static變量的作用范圍為該函數(shù)體, 該變量只分配一次, 其值在下次調(diào)用的時候仍維持上次的值.

2. 模塊內(nèi)的static可被模塊內(nèi)所有函數(shù)訪問, 但不能被模塊外其他函數(shù)訪問.

3. 類中的static成員變量可以視作類變量, 跟對象實例無關(guān), 屬于整個類所有, 對類的所有對象只有一份拷貝. 已經(jīng)實例化的各個對象之間的該static變量不會相互影響, 但對其的改變會影響到class本身. 若再次實例化新的對象, 則該新對象就擁有最新的static類變量.

4. 類中的static成員函數(shù)屬于整個類所有, 該函數(shù)不接收this指針, 只能訪問類的static成員變量.

### const

const, 常量不能修改. 超出作用域后會釋放. 即const對于對象生存期內(nèi)是常量, 對于整個類而言可變.

1. 可以指定指針, 指針?biāo)赶驍?shù)據(jù), 或二者都為const.

2. 函數(shù)中, const修飾形參, 則該輸入?yún)?shù)在函數(shù)內(nèi)部不能修改.

3. 類的成員函數(shù)若指定const, 則為常函數(shù), 不能修改類的成員變量.? (常見于返回一個const值的函數(shù))

### extern

extern: 該模塊中的變量和函數(shù)可在其他模塊中使用.

### 讀寫權(quán)限

readwrite, readonly: 控制成員變量的訪問權(quán)限, 對setter/getter的作用.

### 原子操作

nonatomic: 非原子性訪問, 不加同步, 多線程并發(fā)訪問.

atomic 線程保護. 互斥鎖.

## 總結(jié)

assign: 一般用于int, BOOL等基本變量類型, 防止循環(huán)引用.

weak: 一般用于storyboard或xib中的UI對象和delegate對象.

delegate對象使用weak是為了防止循環(huán)引用。

assign與weak區(qū)別:當(dāng)對象被釋放后丁侄,weak會自動將指針指向nil惯雳,而assign不會。

所以向nil發(fā)送消息導(dǎo)致野指針錯誤unrecognized selector sent to instance鸿摇。防止野指針

strong: 一般用于id類型(非delegate)和對象類型(NSString, UITableView等). 默認, 對應(yīng)于retain.

如果代碼寫的UI對象(使用alloc+init)石景,要使用strong,否則可能在release的時候出如下警告:

Assigning retained object to weak variable; object will be released after assignment.

而如果是IB拉過來的UI對象拙吉,會自動設(shè)置為weak潮孽。

_unsafe_unretained與weak功能一致, 區(qū)別在于當(dāng)指向的對象銷毀之后, weak將變量置為nil, 防止調(diào)用野指針.

block一般用copy。block一般使用copy關(guān)鍵之進行修飾筷黔,block使用copy是從MRC遺留下來的“傳統(tǒng)”恩商,在MRC中,方法內(nèi)容的block是在棧區(qū)的必逆,使用copy可以把它放到堆區(qū)怠堪。但在ARC中寫不寫都行:編譯器自動對block進行了copy操作揽乱。

copy:用@property聲明 NSString、NSArray粟矿、NSDictionary 經(jīng)常使用copy關(guān)鍵字凰棉,是因為他們有對應(yīng)的可變類型:NSMutableString、NSMutableArray陌粹、NSMutableDictionary撒犀,他們之間可能進行賦值操作,為確保對象中的字符串值不會無意間變動掏秩,應(yīng)該在設(shè)置新屬性值時拷貝一份或舞。

如果我們使用是strong,那么這個屬性就有可能指向一個可變對象,如果這個可變對象在外部被修改了,那么會影響該屬性。

copy此特質(zhì)所表達的所屬關(guān)系與strong類似蒙幻。然而設(shè)置方法并不保留新值映凳,而是將其“拷貝” (copy)。 當(dāng)屬性類型為NSString時邮破,經(jīng)常用此特質(zhì)來保護其封裝性诈豌,因為傳遞給設(shè)置方法的新值有可能指向一個NSMutableString類的實例。這個類是NSString的子類抒和,表示一種可修改其值的字符串矫渔,此時若是不拷貝字符串,那么設(shè)置完屬性之后摧莽,字符串的值就可能會在對象不知情的情況下遭人更改庙洼。所以,這時就要拷貝一份“不可變” (immutable)的字符串镊辕,確保對象中的字符串值不會無意間變動油够。只要實現(xiàn)屬性所用的對象是“可變的” (mutable),就應(yīng)該在設(shè)置新屬性值時拷貝一份丑蛤。

循環(huán)引用:

typeof (&*self) __weak weakSelf = self;

autorelease:在retainCount為1時叠聋,不會繼續(xù)減一。而是標(biāo)記為需釋放受裹,準(zhǔn)確的釋放時機暫不明確碌补,可能與runloop有關(guān)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末棉饶,一起剝皮案震驚了整個濱河市厦章,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌照藻,老刑警劉巖袜啃,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異幸缕,居然都是意外死亡群发,警方通過查閱死者的電腦和手機晰韵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來熟妓,“玉大人雪猪,你說我怎么就攤上這事∑鹩” “怎么了只恨?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長抬虽。 經(jīng)常有香客問我官觅,道長,這世上最難降的妖魔是什么阐污? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任休涤,我火速辦了婚禮,結(jié)果婚禮上疤剑,老公的妹妹穿的比我還像新娘滑绒。我一直安慰自己闷堡,他們只是感情好隘膘,可當(dāng)我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著杠览,像睡著了一般弯菊。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上踱阿,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天管钳,我揣著相機與錄音,去河邊找鬼软舌。 笑死才漆,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的佛点。 我是一名探鬼主播醇滥,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼超营!你這毒婦竟也來了鸳玩?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤演闭,失蹤者是張志新(化名)和其女友劉穎不跟,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體米碰,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡窝革,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年购城,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片虐译。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡工猜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出菱蔬,到底是詐尸還是另有隱情篷帅,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布拴泌,位于F島的核電站魏身,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蚪腐。R本人自食惡果不足惜箭昵,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望回季。 院中可真熱鬧家制,春花似錦、人聲如沸泡一。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鼻忠。三九已至涵但,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間帖蔓,已是汗流浹背矮瘟。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留塑娇,地道東北人澈侠。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像埋酬,于是被迫代替她去往敵國和親哨啃。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,916評論 2 344

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