第一章-自動引用計數(shù)

1.1什么是自動引用計數(shù)


內(nèi)存管理中對引用采用自動計數(shù)的計數(shù)
在LLVM編譯器中設(shè)置ARC為有效狀態(tài), 就無需再次鍵入retain或者release代碼

1.2內(nèi)存管理/引用計數(shù)


1.2.1概要

引用計數(shù)例子: 開關(guān)燈

  • 最早進(jìn)入辦公室的人開燈
  • 之后進(jìn)入辦公室的人需要照明
  • 下班早離開辦公室的人不需要照明
  • 最后離開辦公室的人關(guān)燈

通過需要照明人數(shù)來判斷是否有人在辦公室

狀態(tài) 操作 分析
第一個人進(jìn)入辦公室 需要照明人數(shù)+1 計數(shù)值從0變成1, 需要開燈
每當(dāng)有人進(jìn)入辦公室 需要照明人數(shù)+1 如計數(shù)值從1變成2
每當(dāng)有人離開辦公室 需要照明人數(shù)-1 如計數(shù)值從2變成1
最后的人離開辦公室 需要照明人數(shù)-1 計數(shù)值從1變成0, 需要關(guān)燈
  • 照明設(shè)備 - 對象
  • 人- 對象的使用環(huán)境
對照明設(shè)備所做的動作 對Objective-C對象所做的動作
開燈 生成對象
需要照明 引用對象
不需要照明 釋放對象
關(guān)燈 回收對象

1.2.2內(nèi)存管理的思考方式

引用計數(shù)比較客觀的思考方式:

  • 自己生成的對象, 自己所持有
  • 非自己生成的對象, 自己也能持有
  • 不再需要自己持有的對象時釋放
  • 非自己持有的對象無法釋放

對象操作與Objective-C方法對應(yīng)

對象操作 Objective-C方法
生成并且持有對象 alloc/new/copy/mutableCopy等方法
持有對象 retain方法
釋放對象 release方法
廢棄對象 dealloc方法

關(guān)于Objective-C內(nèi)存管理方法包含在Cocoa框架中, Cocoa框架中Foundation框架類庫的NSObject類負(fù)責(zé)內(nèi)存管理的職責(zé)

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

alloc/new/copy/mutableCopy等方法生成的對象, 只有自己持有

// 以下方法, 所有objx對象引用計數(shù)器都會+1
id obj1 = [[NSObject alloc] init];
id obj2 = [[NSObject new];
id obj3 = [objc copy];
id obj4 = [objc mutableCopy];

非自己生成的對象, 自己也能持有

除alloc/new/copy/mutableCopy等方法之外的方法取得的對象, 因為非自己生成并持有, 所以自己不是該對象的持有者, 需要通過retain方法來持有

// 取得非自己生成并持有的對象
id obj = [NSMutableArray array]; // 取得的對象存在, 但自己不持有對象
[obj retain]; // 通過-retian方法使自己持有對象

不再需要自己持有的對象時釋放

自己持有的對象一旦不再需要, 持有者有義務(wù)釋放該對象, 釋放使用release方法

id obj1 = [[NSObject alloc] init]; // 自己生成并持有對象
[obj1 release]; // 釋放對象

id obj2 = [NSMutableArray array]; // 取得的對象存在, 但自己不持有對象
[obj2 retain]; // 通過-retian方法使自己持有對象
[obj2 release]; // 釋放對象

用alloc/new/copy/mutableCopy等方法生成并持有的對象, 或者使用retain方法持有的對象, 一旦不再需要, 務(wù)必要用release方法進(jìn)行釋放

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

用alloc/new/copy/mutableCopy等方法生成并持有的對象, 或者使用retain方法持有的對象, 由于持有者是自己, 所以在不需要該對象時需要將其釋放. 除此之外得到的對象絕對不能釋放, 否則會造成崩潰

1.2.3 alloc/retain/release/dealloc實現(xiàn)

通過GNUstep來說明的
GNUstep是Cocoa框架的互換框架, 與Cocoa實現(xiàn)方式比較一致, 通過其來了解Cocoa框架的實現(xiàn)

1.2.4蘋果的實現(xiàn)

通過對alloc類方法設(shè)置斷點追蹤程序的運行, 得出執(zhí)行所調(diào)用的方法和函數(shù)

+ alloc
+ allocWithZone:
class_createInstance
calloc

alloc類方法首先調(diào)用allocWithZone:類方法, 然后調(diào)用class_createInstance函數(shù), 最后通過calloc來分配內(nèi)存塊

retainCount/retain/release實例方法所調(diào)用的方法和函數(shù)

- retainCount
__CFDoExternRefOperation
CFBasicHashGetCountOfKey

- retain
__CFDoExternRefOperation
CFBasicHashAddValue

- release
__CFDoExternRefOperation
CFBasicHashRemoveValue // 該方法返回0時, -realse調(diào)用dealloc

1.2.5autorelease

autorealse自動釋放, 更類似于C中的局部變量, 即超出作用域時對象實例的realease實例方法被調(diào)用
autorelease的具體使用方法:

  1. 生成并持有NSAutoreleasePool對象
  2. 調(diào)用已分配對象的autorelease實例方法
  3. 廢棄NSAutoreleasePool對象
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
id objc = [[NSObject alloc] init];
[obj autorelease];
[pool drain]; // 相當(dāng)于[obj release];

在Cocoa框架中, 相當(dāng)于程序主循環(huán)的NSRunLoop或者在其他程序可運行的地方, 對NSAutoreleasePool對象進(jìn)程生成, 持有和廢棄處理.
在大量產(chǎn)生autorelease對象時, 只要不廢棄NSAutoreleasePool對象, 那么生成的對象就不能被釋放, 有時會產(chǎn)生內(nèi)存不足的現(xiàn)象. 例如: 讀入大量圖像的同事改變其尺寸, 圖像文件讀入到NSData對象, 并從中生成UIImage對象, 改變對象尺寸后生成新的UIImage對象, 這種情況下會產(chǎn)生大量autorelease對象.

for (int i = 0; i < 圖像數(shù); ++i) {
  // 讀入圖像
  // 大量產(chǎn)生autorelease對象
  // 由于沒有廢棄NSAutoreleasePool對象
  // 最終導(dǎo)致內(nèi)存不足
  
  [pool drain]; // 通過該方法, autorelease的對象被一起release
}

1.2.6autorelease實現(xiàn)

通過GNUstep, 我們能夠看到NSObject類的autorealse實例方法, 本質(zhì)就是調(diào)用NSAutoreleasePool對象的addObject類方法

- (id)autorelease {
  [NSAutoreleasePool addobject: self];
}

1.2.7蘋果的實現(xiàn)

1.3ARC規(guī)則


1.3.1概要

引用計數(shù)式內(nèi)存管理的本質(zhì)部分在ARC中并沒有改變, ARC只是自動地幫我們處理引用計數(shù)的相關(guān)部分

  • 一個應(yīng)用程序可以ARC和MRC混合使用
  • 設(shè)置ARC有效的 編譯方法:
    • 使用clang3.0及其以上版本
    • 指定編譯器屬性為'-fobjc-arc'

1.3.2內(nèi)存管理的思考方式

  • 自己生成的對象, 自己所持有
  • 非自己生成的對象, 自己也能持有
  • 不再需要自己持有的對象時釋放
  • 非自己持有的對象無法釋放

這一思考模式在ARC時也是可行的, 只是在源碼的技術(shù)方法上稍有不同. 具體有什么變化需要先理解ARC中追加的所有權(quán)聲明

1.3.3所有權(quán)修飾符

Objective-C編程中為了處理對象, 可將變量類型定義為id類型或者各種對象類型

ARC有效時, id類型和對象類型同C語言其他類型不同, 其類型必須附加所有權(quán)修飾符, 所有權(quán)修飾符一共4種:

  • __strong修飾符
  • __weak修飾符
  • __unsafe_unretained修飾符
  • __autoreleasing修飾符

__strong修飾符

__strong修飾符是id類型和對象類型默認(rèn)的所有權(quán)修飾符

id obj = [[NSObject alloc] init];
// id和對象類型在沒有明確指定所有權(quán)修飾符時, 默認(rèn)為__strong修飾符
id __strong obj = [[NSObject alloc] init];

在MRC模式下, 改源碼可以記述為

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

如上述代碼所示, 所有__strong修飾符的變量obj在超出其變量作用域時, 即在該變量被廢棄時, 會釋放其被賦予的對象
如'strong'這個名詞所示, __strong修飾符表示對對象的"強引用". 持有強引用的變量在超出其作用于時被廢棄, 隨著強引用的失效, 引用的對象隨之釋放

關(guān)注下源代碼中關(guān)于對象的所有者部分

{
  // 自己生成并且持有對象
  id __strong obj = [[NSObject alloc] init];
  
  // 取得非自己生成并持有的對象
  id __strong obj2 = [NSMutableArray array];
} /*
   * 變量超出其作用于, 強引用失效
   * 自動地釋放自己持有的對象
   * 對象的所有者不存在, 因此廢棄該對象
   */

__strong修飾符的變量, 不僅只在變量作用域中, 在復(fù)制上也能夠正確的管理其對象的所有者.

另外__strong修飾符同之后的__weak修飾符和__autoreleasing修飾符一起, 可以保證將附有這些修飾符的自動變量初始化為nil

id __strong obj0;
id __weak obj1;
id __autoreleasing obj2;

// 下面代碼與以上相同
id __strong obj0 = nil;
id __weak obj1 = nil;
id __autoreleasing obj2 = nil;

__weak修飾符

如果僅僅使用__strong修飾符, 無法解決 "循環(huán)引用" 的問題, 從而引發(fā)內(nèi)存泄露

  • 所謂內(nèi)存泄漏就是應(yīng)當(dāng)廢棄的對象在超出其生命周期后繼續(xù)存在

__weak修飾符與__strong修飾符相反, 提供弱引用. 弱引用不能持有對象實例.

  • 通過__weak修飾符從而解決循環(huán)引用的問題
  • __weak修飾符還有另一優(yōu)點: 在持有某對象的弱引用時, 若該對象被廢棄, 則此弱引用將自動失效且處于nil被賦值的狀態(tài)

可以通過__weak修飾符可避免循環(huán)引用, 通過檢查賦有__weak修飾符的變量是否為nil, 可以判斷被復(fù)制的對象是否已被廢棄

__unsafe_unretained修飾符

__unsafe_unretained修飾符, 是不安全的所有權(quán)修飾符. 盡管ARC的內(nèi)存管理是編譯器工作, 但附有__unsafe_unretained修飾符的變量不屬于編譯器的內(nèi)存管理對象

  • 附有__unsafe_unretained修飾符的變量同附有__weak修飾符的變量一樣, 不能持有對象.
  • 附有__unsafe_unretained修飾的變量如果被廢棄, 該引用不會被自動賦值為nil

在使用__unsafe_unretained修飾符時, 賦值給附有__strong修飾符的變量時, 有必要確認(rèn)被復(fù)制的對象確實存在

__autoreleasing修飾符

ARC有效時不能使用autorelease方法, 也不能使用`NSAutoreleasePool'類. 雖然autorelease無法直接使用, 但是在arc有效時autorelease功能是起作用的

@autoreleasepool {
  id __autoreleasing obj = [[NSObject alloc] init];
}

指定@autoreleasepool快來替代NSAutoreleasePool類對象生成, 持有以及廢棄這一范圍. 對象賦值給附有__autoreleasing修飾符的變量, 等價于在MRC時調(diào)用對象的autorelease方法, 即對象唄注冊到autoreleasepool

在訪問附有__weak修飾符的變量時必須訪問注冊到autoreleasepool的對象, 因為__weak修飾符只有對象的弱引用, 而在訪問引用對象的過程中, 該對象有可能被廢棄, 如果要把訪問對象注冊到autoreleasepool中, an么在@autore快結(jié)束之前都能卻別該對象的存在

id的指針或?qū)ο蟮闹羔樤跊]有顯示指定時會被附加上__autoreleasing修飾符

賦值給對象指針時, 所有權(quán)修飾符必須一致

1.3.4規(guī)則

在ARC有效的情況下編譯代碼, 必須遵守以下原則

  • 不能使用 retain/release/retainCount/autorealease
  • 不能使用NSAllocateObject/NSDeallocateObject
  • 必須遵守內(nèi)存管理方法的命名規(guī)則
  • 不要顯式調(diào)用dealloc
  • 使用@autoreleasepool快替代NSAutoreleasePool
  • 不能使用區(qū)域(NSZone)
  • 對象類型不能為C語言結(jié)構(gòu)體(struct/union)的成員
  • 顯示轉(zhuǎn)換idvoid *

不能使用 retain/release/retainCount/autorealease

編譯器自動使用了這些方法, 再次使用不符合內(nèi)存管理規(guī)范
在ARC有效時, 使用這些方法會編譯出錯

不能使用NSAllocateObject/NSDeallocateObject

一般通過NSObject類的alloc類方法來生成并持有Objective-C對象
在ARC有效時, 使用這些方法會編譯出錯

必須遵守內(nèi)存管理方法的命名規(guī)則

如1.2.2所述, 在ARC無效時, 用于對象生成/持有的方法必須遵守以下命名規(guī)則

  • alloc
  • new
  • copy
  • mutableCopy

以上名稱開始的方法, 在返回對象時, 必須返回給調(diào)用方法所應(yīng)當(dāng)持有的對象

在ARC有效時追加一條:

  • init

以init開始的方法規(guī)則要比上述方法更嚴(yán)格, 該方法必須是實例方法, 并且必須返回對象, 返回的對象應(yīng)為id(instancetype)或該方法聲明類的對象類型, 亦或是該類的父類型或子類型, 該返回對象不注冊到autoreleasepool上, 基本知識對alloc方法返回的對象進(jìn)行初始化處理并返回該對象

不要顯式調(diào)用dealloc

無論ARC是否有效, 只要對象持有者不持有該對象, 對象就會被廢棄, 對象被廢棄時會自動調(diào)用該對象的dealloc方法

  • 在ARC無效時, dealloc方法中必須調(diào)用[super dealloc]
  • 在ARC有效時, dealloc方法中不能調(diào)用[super dealloc], 否則編譯出錯

使用@autoreleasepool快替代NSAutoreleasePool

在ARC有效時不能使用NSAutoreleasePool類, 參考1.3.3

不能使用區(qū)域(NSZone)

雖說ARC有效時不能使用區(qū)域(NSZone), 但是如1.2.3所屬, 不論ARC是否有效, 區(qū)域在現(xiàn)在的運行時系統(tǒng)中已被忽略

對象類型不能為C語言結(jié)構(gòu)體(struct/union)的成員

C語言結(jié)構(gòu)體中如果存在Objective-C對象類型變量, 會引起編譯錯誤

因ARC把內(nèi)存管理的工作分配給編譯器, 所以編譯器必須能夠知道并管理對象的生存周期

要把對象類型變量加入到結(jié)構(gòu)體成員中時 可強制轉(zhuǎn)換為void *或者附加__unsafe_unretained修飾符, 如

// 注意, 附有__unsafe_unretained修飾符的變量不屬于編譯器的內(nèi)存管理對象, 如果使用時不注意賦值對象的所有者, 可能會遭遇內(nèi)存泄漏或程序崩潰
struct Data {
  NSMutableArray __unsafe_unretained *array;
};

顯示轉(zhuǎn)換idvoid *

在ARC無效時, 以下代碼不會出錯

id obj = [[NSObject alloc] init];
void *p = obj;

id o = p;
[o release];

但是在ARC有效時會引起編譯錯誤

id類型或?qū)ο箢愋妥兞抠x值給void *或者逆向賦值時都需要進(jìn)行特定的轉(zhuǎn)換, 如果只想單純的賦值, 則可進(jìn)行__bridge轉(zhuǎn)換

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

id o = (__bridge id)p;

但是轉(zhuǎn)換為void *的__bridge轉(zhuǎn)換, 安全性甚至比__unsafe_unretained更低, 如果使用不注意很可能引起程序崩潰

__bridge還有另外兩種轉(zhuǎn)換

  • __bridge_retained
    • 可使要轉(zhuǎn)換賦值的變量也持有所復(fù)制的對象
  • __bridge_transfer
    • 被轉(zhuǎn)換的變量所持有的對象在該變量唄賦值給轉(zhuǎn)換目標(biāo)變量之后隨之釋放

通過以上兩種轉(zhuǎn)換, 不適用id類型或者對象類型變量也可以生成, 持有以及釋放對象. 雖然可以這樣做, 但是在ARC中并不推薦這種方法

// ARC有效
void *p = (__bridge_retained void *)[[NSObject alloc] init];
(void)(__bridge_gransfer id)p

// ARC無效
id p = [[NSObject alloc] init];
[p release];

這些轉(zhuǎn)換多數(shù)在使用Objective-C對象與Core Foundation對象之間的相互轉(zhuǎn)變中

這部分還講了CoreFoundation和Foundation對象之間的轉(zhuǎn)換及使用注意

1.3.5屬性

當(dāng)ARC有效時, Objective-C類的屬性也發(fā)生了變化, 以下可作為屬性聲明中的屬性來使用

屬性聲明的屬性 所有權(quán)修飾符
assign __unsafe_unretained修飾符
copy __strong修飾符(但是賦值的是被復(fù)制的對象)
retain __strong修飾符
strong __strong修飾符
unsafe_unretained __unsafe_unretained修飾符
weak __weak修飾符

1.3.6數(shù)組

__unsafe_unretain修飾符以外的__strong/__weak/__autoreleasing修飾符保證其指定的變量初始化為nil.

根據(jù)不同的目的選擇使用NSMutableArray/NSMutableDictionary/NSMutableSet等Foundation框架的容器, 這些容器會恰當(dāng)?shù)某钟凶芳拥膶ο蟛槲覀児芾磉@些對象

__autoreleasing修飾的情況下, 因為與設(shè)想的使用方式有差異, 最好不要使用動態(tài)數(shù)組, 由于__unsafe_unretained修飾符在編譯器的內(nèi)存管理對象之外, 所以與void *類型一樣, 只能作為C語言的指針類型來使用

1.4ARC的實現(xiàn)


ARC是Objective-C運行時庫和編譯器進(jìn)行的內(nèi)存管理, ARC由一下工具, 類庫來實現(xiàn)

  • clang(LLVM編譯器)3.0以上
  • objc4 Objective-C運行時庫493.9以上

本節(jié)圍繞clang匯編輸出和objc4庫源碼進(jìn)行說明, 具體代碼詳見書(讀這章之前需要一些runtime基礎(chǔ))

1.4.1 __strong修飾符

賦值給附有__strong修飾符的變量在實際使用中運行原理

這一塊比較繞, 可以先看代碼然后看后面的總結(jié), 最后再繞回來看方法下面的論述

alloc/new/copy/mutableCopy等方法

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

通過程序匯編輸出得到原源代碼

/* 編譯器的模擬代碼 */
id obj = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(obj, @selector(init);
objc_release(obj)

通過原源代碼所以, 兩次調(diào)用objc_msgSend方法(alloc和init), 變量作用域結(jié)束時通過objc_release釋放對象, 雖然ARC不能使用release方法, 但是由此可知, 編譯器自動插入了release.

其它構(gòu)造方法

{
  id __srong obj = [NSMutableArray array];
}

編譯器原源代碼

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

最開始的array方法調(diào)用和最后變量作用域結(jié)束時的release與之前相同, 但是中間的objc_retainAutoreleasedReturnValue函數(shù)是什么?

  • 它是用于 自己持有(retain)對象 的函數(shù), 但它持有的對象應(yīng) 為返回注冊在autoreleasepool中對象的方法或是函數(shù)的返回值, 調(diào)用alloc/new/copy/mutableCopy以外的方法, 由編譯器插入該函數(shù).
  • 這種方法是成對的, 與之相對的是objc_autoreleaseReturnValue, 它用于alloc/new/copy/mutableCopy以外的類的構(gòu)造方法等用于返回的對象的實現(xiàn)上
+ (id)array {
  return [[NSMutableArray Alloc] init];
}

轉(zhuǎn)換后的原源碼使用了objc_autoreleaseReturnValue函數(shù)

+ (id)array {
  id obj = id objc = objc_msgSend(NSMutableArray, @selector(array));
  objc_msgSend(obj, @selector(init));
  return objc_aotureleaseReturnValue(obj);
}

返回 注冊到autoreleasepool中對象 的方法使用了objc_autoreleaseReturnValue函數(shù)返回 注冊到autoreleasepool中的對象, 但是objc_autoreleaseReturnValue函數(shù)同objc_autorelease函數(shù)不同, 一般不僅限于注冊對象到autoreleasepool中.

objc_autoreleaseReturnValue函數(shù)會檢查使用該函數(shù)的方法/函數(shù) 調(diào)用方 的執(zhí)行命名列表, 如果方法/函數(shù)的 調(diào)用方 在調(diào)用了方法/函數(shù)后緊接著調(diào)用objc_retainAutoreleasedReturnValue函數(shù), 那么就不將返回的對象注冊到autoreleasepool中, 而是直接傳遞到方法/函數(shù)的 調(diào)用方

objc_retainAutoreleasedReturnValue函數(shù)與objc_retain函數(shù)不同, 它即便不注冊到autoreleasepool中而返回對象, 也能夠正確的獲取對象
通過objc_retainAutoreleasedReturnValue函數(shù)與objc_autoreleaseReturnValue函數(shù)的寫作, 可以不將對象注冊到autoreleasepool中而直接傳遞, 這一過程達(dá)到了最優(yōu)化.

省略autoreleasepool注冊

說白了, 就是objc_retainAutoreleasedReturnValue函數(shù)持有的對象應(yīng)是函數(shù)/方法的返回值, 這個返回值應(yīng)當(dāng)注冊在autoreleasepool中
objc_autoreleaseReturnValue函數(shù)會判斷自己所在的這個函數(shù)/方法的調(diào)用方之后有沒有調(diào)用objc_retainAutoreleasedReturnValue, 如果沒有, 就將返回值注冊到autoreleasepool中, 如果有就不注冊了, 而且它能讓objc_retainAutoreleasedReturnValue函數(shù)正確的獲取到對象

1.4.2 __weak修飾符

延伸閱讀: weak的生命周期:具體實現(xiàn)方法

  • 若附有__weak修飾符的變量所引用的對象被廢棄, 則將nil賦值給該變量
  • 使用附有__weak修飾符的變量, 即是使用注冊到autoreleasepool中的對象
{
  // 假設(shè)obj附加__strong修飾符且被賦值
  id __weak obj1 = obj;
}

轉(zhuǎn)換后的原源代碼

id obj1;
objc_initWeak(&obj1, obj);
objc_destroyWeak(&obj1);

objc_initWeak函數(shù)內(nèi)部

obj1 = 0;
objc_storeWeak(&obj1, obj;

objc_destroyWeak函數(shù)內(nèi)部


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市伪煤,隨后出現(xiàn)的幾起案子免猾,更是在濱河造成了極大的恐慌绍载,老刑警劉巖吏夯,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件静浴,死亡現(xiàn)場離奇詭異磷籍,居然都是意外死亡适荣,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門院领,熙熙樓的掌柜王于貴愁眉苦臉地迎上來弛矛,“玉大人,你說我怎么就攤上這事比然≌擅ィ” “怎么了?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵强法,是天一觀的道長万俗。 經(jīng)常有香客問我,道長饮怯,這世上最難降的妖魔是什么闰歪? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮蓖墅,結(jié)果婚禮上库倘,老公的妹妹穿的比我還像新娘。我一直安慰自己置媳,他們只是感情好于樟,可當(dāng)我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著拇囊,像睡著了一般迂曲。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上寥袭,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天路捧,我揣著相機(jī)與錄音,去河邊找鬼传黄。 笑死杰扫,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的膘掰。 我是一名探鬼主播章姓,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼佳遣,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了凡伊?” 一聲冷哼從身側(cè)響起零渐,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎系忙,沒想到半個月后珠闰,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體长捧,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了轩猩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片癌别。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡荸镊,死狀恐怖症见,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情苍苞,我是刑警寧澤固翰,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站羹呵,受9級特大地震影響骂际,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜冈欢,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一歉铝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧凑耻,春花似錦太示、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至邻吭,卻和暖如春餐弱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背囱晴。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工膏蚓, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人畸写。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓驮瞧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親枯芬。 傳聞我的和親對象是個殘疾皇子论笔,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,802評論 2 345

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