底層研究 - 對(duì)象的底層探索(下)

前言

底層研究 - 對(duì)象的底層探索(上)已經(jīng)探索完對(duì)象alloc底層原理,對(duì)象的內(nèi)存對(duì)齊和結(jié)構(gòu)體的內(nèi)存對(duì)齊,同時(shí)也知道了結(jié)構(gòu)體內(nèi)順序?qū)Y(jié)構(gòu)體的內(nèi)存分配大小產(chǎn)生影響翁逞,接下來繼續(xù)探究對(duì)象的內(nèi)存分布

一些用到的lldb指令

  • p/x 以十六進(jìn)制打印數(shù)據(jù)
  • p/o 以八進(jìn)制打印數(shù)據(jù)
  • p/t 以二進(jìn)制打印數(shù)據(jù)
  • p/f 以浮點(diǎn)形式打印數(shù)據(jù)
  • x/4gx 輸出對(duì)象的內(nèi)存地址,x/4gx中4代表輸出4個(gè)卿叽,g代表每一個(gè)是8字節(jié)大小彤断,x代表以16進(jìn)制打印漱贱。

1、影響對(duì)象內(nèi)存的因素

創(chuàng)建一個(gè)Person類妓笙,并且實(shí)例化一個(gè)對(duì)象并對(duì)其進(jìn)行賦值若河,發(fā)現(xiàn)打印的結(jié)構(gòu)是48.

@interface Person : NSObject
@property (nonatomic ,copy) NSString *name;
@property (nonatomic ,copy) NSString *hobby;
@property (nonatomic ,assign) int age;
@property (nonatomic ,assign) double hight;
@property (nonatomic ,assign) short number;
@property (nonatomic ,assign) char a;
@end

@implementation Person
@end

int main(int argc, char * argv[]) {
    NSString * appDelegateClassName;
    @autoreleasepool {
        // Setup code that might create autoreleased objects goes here.
        appDelegateClassName = NSStringFromClass([AppDelegate class]);
        
        Person *p = [Person new];
        p.name = @"小明";
        p.hobby = @"boy";
        p.hight = 1.8;
        p.age = 18;
        p.number = 123;
        p.a = 5;
        NSLog(@"%lu",malloc_size((__bridge const void *)(p)));
    }
    return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}

//打印結(jié)果:48

我們打個(gè)斷點(diǎn)看看p的內(nèi)存分布情況,由于第一個(gè)8字節(jié)是isa寞宫,直接從第二個(gè)8字節(jié)開始打印萧福。

p的內(nèi)存分布

通過打印結(jié)果可以發(fā)現(xiàn),第二個(gè)地址打印的值并不是我們賦值的成員變量的值辈赋,而且age鲫忍、numbera這三個(gè)成員變量的值并沒有發(fā)現(xiàn)钥屈。我們唯一的著手的就只有第二個(gè)莫名其妙的地址悟民,嘗試把它拆開分成三斷打印
消失的變量值

可以發(fā)現(xiàn)agenumber焕蹄、a這三個(gè)成員變量的值出現(xiàn)了逾雄,說明它們?cè)谕粋€(gè)內(nèi)存地址里阀溶。由此我們也可以得出一個(gè)結(jié)論腻脏,成員變量的值在存儲(chǔ)時(shí)自動(dòng)重新排序。那為什么這么做呢银锻?可以推測(cè)是為了優(yōu)化內(nèi)存永品。
對(duì)象的內(nèi)存是8字節(jié)對(duì)齊,a和age以及number總共占用1+4+2 = 7 個(gè)字節(jié)击纬,并沒有超出8字節(jié)鼎姐,可以放在同一個(gè)內(nèi)存地址內(nèi),從而節(jié)省了內(nèi)存的消耗更振。

2炕桨、對(duì)象的內(nèi)存分布

既然對(duì)象的屬性在賦值后會(huì)自動(dòng)重排,那對(duì)象本身的成員變量或者繼承自父類的屬性會(huì)不會(huì)也重排呢?

@interface Person : NSObject
{
    @public
    int age;
    NSString *name;
    NSString *sex;
    int age1;
}
@end

@interface Person1 : NSObject
{
    @public
    int age;
    NSString *name;
    int age1;
    NSString *sex;
}
@end

@interface Person2 : Person
{
    @public
    char a;
}
@end

@interface Person3 : Person1
{
    @public
    char a;
}
@end

@implementation Person
@end

@implementation Person1
@end

@implementation Person2
@end

@implementation Person3
@end

int main(int argc, char * argv[]) {
    NSString * appDelegateClassName;
    @autoreleasepool {
        // Setup code that might create autoreleased objects goes here.
        appDelegateClassName = NSStringFromClass([AppDelegate class]);
    
        Person *person = [[Person alloc] init];
        person->age1 = 18;
        person->name = @"小明";
        person->age = 19;
        person->sex = @"男";
    
        Person1* person1 = [[Person1 alloc] init];
        person1->age1 = 18;
        person1->name = @"小明";
        person1->age = 19;
        person1->sex = @"男";
    
        Person2* person2 = [[Person2 alloc] init];
        person2->age1 = 18;
        person2->name = @"小明";
        person2->age = 19;
        person2->sex = @"男";
        person2->a = 5;
    
        Person3* person3 = [[Person3 alloc] init];
        person3->age1 = 18;
        person3->name = @"小明";
        person3->age = 19;
        person3->sex = @"男";
        person3->a = 5;
    }
    return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
person和person1內(nèi)存分布圖

從上面的打印結(jié)果可以得出兩個(gè)結(jié)論

  • 通過對(duì)比person和person1可以發(fā)現(xiàn)肯腕,自己聲明的成員變量并不會(huì)被自動(dòng)重排順序献宫,并且在內(nèi)存中的分布是按照成員變量聲明的順序存儲(chǔ)的
  • 通過對(duì)比person2和person3可以發(fā)現(xiàn),當(dāng)子類繼承自父類時(shí)实撒,子類的內(nèi)存是否被優(yōu)化姊途,取決于父類的成員變量位置,因?yàn)閜erson最后一個(gè)成員變量是int知态,不夠8字節(jié)捷兰,而person1是nsstring類型,已經(jīng)是8字節(jié)负敏。

person2的現(xiàn)象這其實(shí)是一個(gè)系統(tǒng)級(jí)別的優(yōu)化贡茅,并不是重排導(dǎo)致

那如果是屬性繼承的話,會(huì)不會(huì)觸發(fā)屬性重排呢?

@interface Person : NSObject
@property (nonatomic ,copy) NSString *name;
@property (nonatomic ,copy) NSString *hobby;
@property (nonatomic ,assign) int age;
@property (nonatomic ,assign) double hight;
@property (nonatomic ,assign) short number;
@end

@interface Person1 : Person
@property (nonatomic ,assign) char a;
@end

@implementation Person
@end

@implementation Person1
@end


int main(int argc, char * argv[]) {
    NSString * appDelegateClassName;
    @autoreleasepool {
        // Setup code that might create autoreleased objects goes here.
        appDelegateClassName = NSStringFromClass([AppDelegate class]);
        
        Person1 *p = [Person1 new];
        p.name = @"小明";
        p.hobby = @"boy";
        p.hight = 1.8;
        p.age = 18;
        p.number = 123;
        p.a = 5;
        NSLog(@"%lu",malloc_size((__bridge const void *)(p)));
    }
    return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}

繼承屬性

從上圖打印的結(jié)果可以發(fā)現(xiàn)事實(shí)上父類自動(dòng)生成的成員變量并沒有和子類自動(dòng)生成的成員變量一起被系統(tǒng)自動(dòng)重排順序顶考,而是各自進(jìn)行重排彤叉。這里出現(xiàn)這樣的原因是當(dāng)子類在繼承父類的數(shù)據(jù)結(jié)構(gòu)時(shí),父類是一塊連續(xù)的內(nèi)存空間村怪,子類是沒有辦法去修改父類的數(shù)據(jù)結(jié)構(gòu)的秽浇,也就是說系統(tǒng)在進(jìn)行屬性重排的時(shí)候只是基于某一個(gè)類,并不會(huì)把子類的成員變量和父類的成員變量重排在一起甚负。

3柬焕、位域和聯(lián)合體

接下來我們先講解下位域和聯(lián)合體。

  • 位域:在一個(gè)結(jié)構(gòu)體中以位為單位來指定其成員所占內(nèi)存梭域,但指定的內(nèi)存大小不能超過該成員類型所占的最大內(nèi)存大小斑举。
struct Struct1 {
    char a;
    char b;
    char c;
    char d;
}struct1;

struct Struct2 {
    // a: 位域名  4:位域長(zhǎng)度
    char a : 1;
    char b : 1;
    char c : 1;
    char d : 1;
}struct2;

一個(gè)正常的結(jié)構(gòu)體,它所占的內(nèi)存空間由它的數(shù)據(jù)結(jié)構(gòu)決定病涨,如果不使用位域富玷,struct1占用4個(gè)字節(jié),但struct2只占用了1個(gè)字節(jié)(實(shí)際上是1位既穆,8位1字節(jié))

struct Struct3 {
    char a : 7;
    char b : 1;
    char c : 1;
    char d : 1;
}struct3;

當(dāng)1個(gè)字節(jié)不夠存儲(chǔ)時(shí)赎懦,會(huì)自動(dòng)存入下一個(gè)字節(jié)
,也就是struct3占用了2個(gè)字節(jié)幻工。

  • 聯(lián)合體:將幾種不同類型的變量存放到同一段內(nèi)存單元中励两,幾個(gè)變量互相覆蓋,聯(lián)合體的作用是節(jié)省一定的內(nèi)存空間囊颅,所占內(nèi)存取決于最大成員變量当悔,且必須是其最大成員變量(基本數(shù)據(jù)類型)的整數(shù)倍
union Person {
    char *name;
    int number;
    double height;
}p1;

根據(jù)規(guī)則計(jì)算出來:Person結(jié)構(gòu)體的內(nèi)存大小為8字節(jié)

當(dāng)聯(lián)合體中有數(shù)組時(shí):

union Person {
    char a[7];
    int number;
    double height;
}p1;

聯(lián)合體Person中最大的成員變量是數(shù)組踢代,內(nèi)存占用7個(gè)字節(jié)盲憎,但因其不是基本數(shù)據(jù)類型,因此Person是double的整數(shù)倍胳挎,該聯(lián)合體占8個(gè)字節(jié)饼疙。

聯(lián)合體和結(jié)構(gòu)體的區(qū)別:
結(jié)構(gòu)體(struct)中所有變量是“共存”的,?聯(lián)合體(union)中是各變量是“互斥”的串远,只能存在?個(gè)宏多。struct內(nèi)存空間的分配是粗放的,不管?不?澡罚,全部分配伸但。這樣帶來的?個(gè)壞處就是對(duì)于內(nèi)存的消耗要??些。但是結(jié)構(gòu)體??的數(shù)據(jù)是完整的留搔。聯(lián)合體??的數(shù)據(jù)只能存在?個(gè)更胖,但優(yōu)點(diǎn)是內(nèi)存使?更為精細(xì)靈活,也節(jié)省了內(nèi)存空間。

4却妨、nonPointerIsa

有了聯(lián)合體和位域的知識(shí)饵逐,我們看下objc底層是怎么使用的,來到_class_createInstanceFromZone方法

_class_createInstanceFromZone

進(jìn)入initInstanceIsa方法內(nèi)彪标,我們發(fā)現(xiàn)其內(nèi)部也是調(diào)用了initIsa方法


initInstanceIsa

進(jìn)入initIsa方法內(nèi)倍权,我們發(fā)現(xiàn)了其內(nèi)部就是對(duì)對(duì)象的isa指針進(jìn)行初始化,同時(shí)我們發(fā)現(xiàn)了isa_t的數(shù)據(jù)類型


initIsa

進(jìn)入isa_t發(fā)現(xiàn)它就是聯(lián)合體捞烟,根據(jù)我們掌握的聯(lián)合體知識(shí)可以發(fā)現(xiàn)它的目的是兼容舊版本的isa(Class cls)薄声。


isa_t

如今的系統(tǒng)采用的是nonPointerIsa,相較于舊版本题画,它節(jié)省了內(nèi)存空間默辨。因?yàn)閷?duì)象的isa是一個(gè)8字節(jié)的Class類型的結(jié)構(gòu)體指針,主要是用來存儲(chǔ)對(duì)象所屬類對(duì)象的內(nèi)存地址的苍息,而存儲(chǔ)類對(duì)象的內(nèi)存地址不需要使用8字節(jié)這么大的內(nèi)存空間缩幸,所以系統(tǒng)就把一些與對(duì)象息息相關(guān)的信息也存儲(chǔ)到isa的內(nèi)存空間內(nèi),而nonPointerIsa的信息都存儲(chǔ)在ISA_BITFIELD這樣一個(gè)結(jié)構(gòu)體內(nèi)竞思。

# if __arm64__
// ARM64 simulators have a larger address space, so use the ARM64e
// scheme even when simulators build for ARM64-not-e.
#   if __has_feature(ptrauth_calls) || TARGET_OS_SIMULATOR
#     define ISA_MASK        0x007ffffffffffff8ULL
#     define ISA_MAGIC_MASK  0x0000000000000001ULL
#     define ISA_MAGIC_VALUE 0x0000000000000001ULL
#     define ISA_HAS_CXX_DTOR_BIT 0
#     define ISA_BITFIELD                                                      \
        uintptr_t nonpointer        : 1;                                       \
        uintptr_t has_assoc         : 1;                                       \
        uintptr_t weakly_referenced : 1;                                       \
        uintptr_t shiftcls_and_sig  : 52;                                      \
        uintptr_t has_sidetable_rc  : 1;                                       \
        uintptr_t extra_rc          : 8
#     define RC_ONE   (1ULL<<56)
#     define RC_HALF  (1ULL<<7)
#   else
#     define ISA_MASK        0x0000000ffffffff8ULL
#     define ISA_MAGIC_MASK  0x000003f000000001ULL
#     define ISA_MAGIC_VALUE 0x000001a000000001ULL
#     define ISA_HAS_CXX_DTOR_BIT 1
#     define ISA_BITFIELD                                                      \
        uintptr_t nonpointer        : 1;                                       \
        uintptr_t has_assoc         : 1;                                       \
        uintptr_t has_cxx_dtor      : 1;                                       \
        uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
        uintptr_t magic             : 6;                                       \
        uintptr_t weakly_referenced : 1;                                       \
        uintptr_t unused            : 1;                                       \
        uintptr_t has_sidetable_rc  : 1;                                       \
        uintptr_t extra_rc          : 19
#     define RC_ONE   (1ULL<<45)
#     define RC_HALF  (1ULL<<18)
#   endif

# elif __x86_64__
#   define ISA_MASK        0x00007ffffffffff8ULL
#   define ISA_MAGIC_MASK  0x001f800000000001ULL
#   define ISA_MAGIC_VALUE 0x001d800000000001ULL
#   define ISA_HAS_CXX_DTOR_BIT 1
#   define ISA_BITFIELD                                                        \
      uintptr_t nonpointer        : 1;                                         \
      uintptr_t has_assoc         : 1;                                         \
      uintptr_t has_cxx_dtor      : 1;                                         \
      uintptr_t shiftcls          : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \
      uintptr_t magic             : 6;                                         \
      uintptr_t weakly_referenced : 1;                                         \
      uintptr_t unused            : 1;                                         \
      uintptr_t has_sidetable_rc  : 1;                                         \
      uintptr_t extra_rc          : 8
#   define RC_ONE   (1ULL<<56)
#   define RC_HALF  (1ULL<<7)

# else
#   error unknown architecture for packed isa
# endif

這個(gè)nonPointerIsa的結(jié)構(gòu)體中有不少成員表谊,下面我們看下這些成員變量的作用:

//nonpointer:表示是否對(duì)isa指針開啟指針優(yōu)化,0:純isa指針衙四,1:不止是類對(duì)象地址铃肯,isa包含了類信息、對(duì)象的引用計(jì)數(shù)等
uintptr_t nonpointer        : 1;                 
//has_assoc:關(guān)聯(lián)對(duì)象標(biāo)志位传蹈,0沒有,1存在
uintptr_t has_assoc         : 1;    
//has_cxx_dtor:該對(duì)象是否有C++或者Objc的析構(gòu)器步藕,如果有析構(gòu)函數(shù)惦界,則需要做析構(gòu)邏輯,如果沒有咙冗,則可以更快的釋放對(duì)象                                 
uintptr_t has_cxx_dtor      : 1;      
//shiftcls:存儲(chǔ)類指針的值沾歪。開啟指針優(yōu)化的情況下,在arm64(真機(jī))架構(gòu)中用33位存儲(chǔ)類指針                                   
uintptr_t shiftcls          : 33; 
//magic:用于調(diào)試器判斷當(dāng)前對(duì)象是真的對(duì)象還是沒有初始化的空間
uintptr_t magic             : 6;    
//weakly_referenced:標(biāo)志對(duì)象是否被指向或者曾經(jīng)指向一個(gè)ARC的弱變量雾消,沒有弱引用的對(duì)象可以更快釋放                                     
uintptr_t weakly_referenced : 1;      
//unused:沒有使用(在之前舊版本灾搏,該位置表示 deallocating: 標(biāo)志對(duì)象是否正在釋放內(nèi)存)                               
uintptr_t unused            : 1;    
//has_sidetable_rc:是否需要使用sidetable來存儲(chǔ)引用計(jì)數(shù),當(dāng)對(duì)象引用計(jì)數(shù)大于10時(shí)立润,則需要借用該變量存儲(chǔ)進(jìn)位                           
uintptr_t has_sidetable_rc  : 1;       
//extra_rc:表示該對(duì)象的引用計(jì)數(shù)值狂窑,實(shí)際上是引用計(jì)數(shù)值減1,例如桑腮,如果對(duì)象的引用計(jì)數(shù)為10泉哈,那么extra_rc為9.如果引用計(jì)數(shù)大于10,則需要使用到上面的has_sidetable_rc                              
uintptr_t extra_rc          : 19;

知道nonPointerIsa后,我們看下如何利用nonPointerIsa來獲取類對(duì)象丛晦!

5奕纫、利用isa得到類對(duì)象

通過nonPointerIsa的定義,我可以知道nonPointerIsa內(nèi)存儲(chǔ)的類對(duì)象地址空間在不同架構(gòu)下占用的位域分別為52烫沙、33匹层、44

# if __arm64__
// ARM64 simulators have a larger address space, so use the ARM64e
// scheme even when simulators build for ARM64-not-e.
#   if __has_feature(ptrauth_calls) || TARGET_OS_SIMULATOR
.....
        uintptr_t shiftcls_and_sig  : 52;                                      ......
#   else
......
        uintptr_t shiftcls          : 33; 
.....
#   endif
# elif __x86_64__
.....
      uintptr_t shiftcls          : 44; 
......
#   endif

在源碼的main文件內(nèi)創(chuàng)建一個(gè)person對(duì)象,因?yàn)槭请娔X是x86_64架構(gòu)的锌蓄,所以對(duì)象占用的位域長(zhǎng)度是44位來存儲(chǔ)又固。我們可以分別使用兩種方式來獲取類對(duì)象:

  • ISA_MASK
    我們可以直接用源碼提供的ISA_MASK & 上對(duì)象地址,就可以獲得類對(duì)象
  • 位運(yùn)算
    通過上面的分析我們已經(jīng)知道isa的內(nèi)存分配情況煤率,要取出完整的類對(duì)象信息仰冠,只需要把其余的數(shù)據(jù)全部清零即可。首先右移3位到最右邊蝶糯,左移20位(3 + 17)到最左邊洋只,再右移17位返回原來的位置

屬性是從低位往高位存,x86_64架構(gòu)又是小端模式昼捍,地址低位存放在低地址(高位存放在高地址)
例如:0x12345678
-> 大端:12 34 56 78
-> 小端:78 56 34 12

兩種方式打印類對(duì)象信息

6识虚、new方法

我們經(jīng)常發(fā)現(xiàn)創(chuàng)建對(duì)象的方式除了alloc方法外,還有new方法妒茬,那么二者有什么區(qū)別呢担锤?
我們直接看下objc的源碼,找到new方法

new方法

通過源碼我們發(fā)現(xiàn)乍钻,new方法調(diào)用callAlloc函數(shù)后調(diào)用了init方法肛循,也就是說new方法本質(zhì)上就是alloc + init。

7银择、總結(jié)

  1. 對(duì)象??存儲(chǔ)了?個(gè)isa指針 + 成員變量的值多糠,isa指針是固定的,占8個(gè)字節(jié)浩考,所以影響對(duì)象內(nèi)存的只有成員變量(屬性會(huì)?動(dòng)?成帶下劃線的成員變量)
  2. 在對(duì)象的內(nèi)部是以8字節(jié)進(jìn)?對(duì)?的夹孔。
    蘋果會(huì)?動(dòng)重排成員變量的順序,將占?不? 8 字節(jié)的成員挨在?起析孽,湊滿 8 字節(jié)搭伤,以達(dá)到優(yōu)化內(nèi)存的?的。
  3. 自己寫的成員變量的順序就按照書寫順序來的袜瞬,蘋果會(huì)重拍屬性的順序怜俐,但是在重排的時(shí)候不會(huì)考慮父類,父類和子類各自重排屬性吞滞。
    4.結(jié)構(gòu)體(struct)中所有變量是“共存”的佑菩,?聯(lián)合體(union)中是各變量是“互斥”的盾沫,只能存在?個(gè)。
  4. 位域的寬度不能超過前?數(shù)據(jù)類型的最??度殿漠。
  5. nonPointerIsa是內(nèi)存優(yōu)化的?種?段赴精,通過位域和聯(lián)合體兼容了舊版本的isa和存儲(chǔ)其他的信息在isa的內(nèi)存空間中。
  6. new = alloc + init
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末绞幌,一起剝皮案震驚了整個(gè)濱河市蕾哟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌莲蜘,老刑警劉巖谭确,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異票渠,居然都是意外死亡逐哈,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門问顷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來昂秃,“玉大人,你說我怎么就攤上這事杜窄〕β妫” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵塞耕,是天一觀的道長(zhǎng)蚀腿。 經(jīng)常有香客問我,道長(zhǎng)扫外,這世上最難降的妖魔是什么莉钙? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮畏浆,結(jié)果婚禮上胆胰,老公的妹妹穿的比我還像新娘。我一直安慰自己刻获,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布瞎嬉。 她就那樣靜靜地躺著蝎毡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪氧枣。 梳的紋絲不亂的頭發(fā)上沐兵,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音便监,去河邊找鬼扎谎。 笑死碳想,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的毁靶。 我是一名探鬼主播胧奔,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼预吆!你這毒婦竟也來了龙填?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤拐叉,失蹤者是張志新(化名)和其女友劉穎岩遗,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體凤瘦,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡宿礁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蔬芥。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片梆靖。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖坝茎,靈堂內(nèi)的尸體忽然破棺而出涤姊,到底是詐尸還是另有隱情,我是刑警寧澤嗤放,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布思喊,位于F島的核電站,受9級(jí)特大地震影響次酌,放射性物質(zhì)發(fā)生泄漏恨课。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一岳服、第九天 我趴在偏房一處隱蔽的房頂上張望剂公。 院中可真熱鬧,春花似錦吊宋、人聲如沸纲辽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拖吼。三九已至,卻和暖如春这吻,著一層夾襖步出監(jiān)牢的瞬間吊档,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來泰國打工唾糯, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留怠硼,地道東北人鬼贱。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像香璃,于是被迫代替她去往敵國和親这难。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

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