类的加载(下)

在上一篇文章类的加载(上)了解了到了_read_images大概流程,也详细讲解了readClass方法 技能回顾

map_images函数实现类加载处理标红.jpg

下面讲解 标红区域 因为讲的是类的加载,当类的加载了解清楚了 其他步骤 也就清晰可见

懒加载类和非懒加载类

首先我们看类加载处理这里的源码

类的加载处理源码注释

在源码注释里我们很清晰的看到了一句话 Realize non-lazy classes (for +load methods and static instances) 翻译过来 就是 实现非懒加载类(当实现了+load方法 或者 static instances)❓
带着疑问 我们修改源码 在 类的加载(上)我们曾在readClass里面也进行了修改 这次我们在 下面继续断点 并 修改源码目的针对性研究
截屏2020-10-20 下午1.31.55.png

非懒加载类环境流程

将LGPerson里的项目 添加上+load 运行 按照源码所说 此时它为非懒加载类


截屏2020-10-20 下午1.35.40.png

项目断在readClass 并继续过断点


截屏2020-10-20 下午1.37.20.png

截屏2020-10-20 下午1.40.48.png

我们看到确实来到了修改源码的断点 并即将进入 realizeClassWithoutSwift 函数 下面我们进行研究

realizeClassWithoutSwift

源码注释此方法的含义


截屏2020-10-20 下午1.47.10.png

解读

  • 首次对类cls进行初始化,
  • 包括分配读写数据。
  • 不执行任何快速端初始化。
  • 返回类的真实类结构。

源码查看及解读 (由于代码太长分段解读)


截屏2020-10-20 下午1.57.22.png
第一步:读取data数据
  • 当前类的判空 是否已经实现 的判断
  • 未实现也不为nil 读取 class的data数据 并强转为 (class_ro_t*)类型 获取 ro
  • 获取元类判断条件
  • 如果是未来的类 ,此时 rw 数据 已经准备好 直接读取 data() 获取 rw ro
  • 正常的类 分配可写入的类数据。
    1. 申请开辟 <class_rw_t>数据结构 rw模板
    2. 根据ro设置rw 从ro中copy到rw中
    3. 将cls的data赋值为rw形式
第二步:递归调用 realizeClassWithoutSwift 完善 继承链
截屏2020-10-20 下午2.29.45.png
  • 递归调用 realizeClassWithoutSwift设置父类、元类
    注: isa找到根元类之后,根元类的isa是指向自己,并不会返回nil,所以有以下递归终止条件,其目的是保证类只加载一次
    1.如果类不存在,则返回nil

    2.如果类已经实现,则直接返回cls
    截屏2020-10-20 下午2.38.53.png
    1. remapClass 如cls不存在,则返回nil
      截屏2020-10-20 下午2.41.06.png
  • 设置父类和元类的isa指向

  • 通过addSubclass 和 addRootClass设置父子的双向链表指向关系,即父类中可以找到子类,子类中可以找到父类

第三步:通过 methodizeClass 方法化类

源码注释此方法的含义



截屏2020-10-20 下午2.49.43.png
  • 修复cls的方法列表、协议列表和属性列表。
  • 附加任何突出类别。

源码查看及解读


截屏2020-10-20 下午3.28.43.png
  • 在realizeClassWithoutSwift 我们已经拿到了 ro rw 没见到 rwe的踪影
  • method_list 方法处理
    注:在这里 我们想起了在 消息发送流程的慢速查找流程,其中查找算法是二分查找,说明sel-imp是有序排列,那么如何排序的呢?
    就是在这里
    截屏2020-10-20 下午3.38.54.png

    它内部是通过fixupMethodList方法排序
    截屏2020-10-20 下午3.41.01.png

    进入fixupMethodList源码实现,是根据selector address排序
    截屏2020-10-20 下午3.43.11.png
  • 无论是methods 还是properties 还是protocols 我么发现都去调用了一个方法attachLists添加上针对的代码 并断点到LGPerson
    截屏2020-10-20 下午4.05.32.png

结果发现 rwe 为NULL 并未运行其 rwe为真的判断 为什么 留疑问

  • 继续过断点来到了 attachToClass


    截屏2020-10-20 下午4.11.02.png

    截屏2020-10-20 下午4.19.50.png

    在methodlist方法主要是将分类添加到主类中 当前环境没有分类所以下面都没有运行

懒加载类环境流程

👆上面的流程我们都是在实现了load的情况下进行跟进的下面👇我们来屏蔽load使其变为懒加载环境


截屏2020-10-20 下午10.23.29.png

并在初始化LGPerson代码断言 运行


截屏2020-10-20 下午10.29.57.png

发现 在main函数之前调用的 mapimages -> _read_images -> readClass
在次向下走一步断点
截屏2020-10-20 下午10.43.28.png

进入到methodizeClass里查看调用栈


截屏2020-10-20 下午10.48.33.png

这不正是我们之前学习的消息慢速转发流程lookImpOrForward发起的调用嘛

总结

  • 什么是懒加载类 和非懒加载类
    截屏2020-10-20 下午10.51.39.png
  • ro rw rwe 定义及为什么存在
    1. app在使用类时,是需要在磁盘中app的二进制文件中读取类的信息,二进制文件中的类存储了类的元类、父类、flags和方法缓存 那么类的额外信息(name、方法、协议和实例变量等)存储在class_ro_t中

    2. class_ro_t简称 ro: read only 干净的内存空间 只读 又称为 clean memory

    3. class_rw_t简称 rw: read write 意义: 由于ios有运行时 会不断的插入 添加 删除 也就是 增删改 查 频繁 对当前 这块内存操作比较严重 为了防止对原始数据的破坏,所以就有了 rw 用于读写编写程序。 drity memory 在进程运行时发生更改的内存。类一经使用运行时就会分配一个额外的内存,那么这个内存变成了drity memory。但是在实际应用中,类的使用量只是10%,这样就在rw中造成了内存浪费,所以苹果就把rw中方法、协议和实例变量等放到了class_rw_ext_t中。

    4. class_rw_ext_t简称 rwe: read write ext,用于运行时存储类的方法、协议和实例变量等信息。


      class ro - rw - rwe.jpg

分类的加载流程

attachToClass

在methodlist方法主要是将分类添加到主类中,其源码实现如下


截屏2020-10-20 下午11.05.34.png
  • 找到一个分类进来一次,即一个一个加载分类,不要混乱
  • 当主类没有实现load, 分类开始加载、迫使主类加载,会走到if流程
    下面研究 attachCategories

attachCategories

截屏2020-10-21 下午4.58.58.png

源码注释解析

  1. 将方法列表、属性和协议从类别附加到类中。
    假设所有cats中的类别都已加载并按加载顺序排序,
    先有最古老的类别。

  2. 只有少数类在启动期间有超过64个类别。
    这使用了一个小堆栈,并避免malloc。

    类别必须按正确的顺序添加,也就是从后到前。为了完成分块操作,我们从前向后迭代cats_list,向后构建本地缓冲区,并在块上调用attachLists。attachLists突出显示的
    列表,因此最终结果按照预期的顺序。

截屏2020-10-21 下午5.09.28.png

在这里我们看到了 rwe 赋值

截屏2020-10-21 下午5.19.08.png
  • 判断rwe是否存在,存在直接取值不存在 则根据ro开辟。


    截屏2020-10-21 下午5.26.46.png

点进去我们也看到了 attachLists方法 从0-1的过程也存在下面进行分析它

attachLists

截屏2020-10-21 下午5.40.21.png

经过分析 我们可以看到 attachLists 方法存在三种情况 下面为 rwe 方法列表 0 -1的过程


rwe方法列表 0-1

回到上面断点处 我们打印 rwe


截屏2020-10-21 下午6.24.57.png

此时没有走下面的时候 rwe的 methods 正是 本类也就是ro->baseMethods 数据的 copy
我们继续向下走


截屏2020-10-22 上午10.51.07.png

画图表示 这个算法


category存入 64个空间的 mlists
  1. 先存进之前开辟好的64个空间的栈里
  2. mlists + ATTACH_BUFSIZ - mcount 获取mlists的首地址+ 64 - 有几个分类 最终等于 这几个分类的真实地址。抹掉没用到的。
  3. 排序
  4. 存入到rwe的methods中.
    1). 从上面的0-1 过程 就是 开始创建 rwe 将本类 ro中的baseMethods存入rwe中 此时 attachlists 是 0-1 是一个 一纬数组。
    2). 这次再进入 就是一个 1对多 的过程。


    list ->many Lists

在下面是 多对多的逻辑示意图


截屏2020-10-22 下午1.15.14.png

总结

  • readClass 主要是读取类,即此时的类仅有地址+名称,还没有data数据
  • 懒加载类 未实现load的的类 数据加载推迟到第一次消息的时候
  • 非懒加载类 map_images的时候 加载所有的类数据
  • methodizeClass 两种情况都会调用 一个是main函数之前 一个是消息发送之慢速查找。
  • 在mehodizeClass里 方法序列化 为了 在慢速查找中的二分查找, 有附加分类 方法 ,主要是将 rwe的初始化(从ro中获取主类初始值)、将主类的 methods、 properties、 protocols 等添加到 rwe中, 其帖进去的方法核心为 attachLists函数算法

类的加载源码解析分析图

类加载处理.jpg

上面我们已经大概理解了类是如何从Mach-0 加载到内存中,下面我们来详细了解 分类 如何加载到类中,以及 类 + 分类搭配使用情况

分类的本质

通过 clang 以及 苹果官方文档 及 objc源码 我们都可以了解到分类的本质就是一个结构体
截屏2020-10-22 下午6.15.17.png
  • instanceMethods: 实例方法列表
  • classMethods: 类方法列表
  • protocols: 协议表
  • instanceProperties: 实例属性 表
  • _classProperties : 类属性表 ; 拓: @property(class,nonatomic,copy) NSString * classPropertie
  • methodsForMeta() : 获取方法列表 判断是否是元类 还是 类。(因为我们知道 实例方法在类中,类方法在元类中)
  • propertiesForMeta() 获取元类或者类的属性 表
  • protocolsForMeta() 获取 元类 或者 类的 协议表 (从这里可以看出协议只存在类对象中)

分类的调用时机

上面的流程分析了 attachCategories的源码干了点什么事情它主要是 是否存才 rwe 不存在 初始化rwe 及 将分类的信息 帖到 rwe中 下面是它的流程
realizeClassWithoutSwift -> methodizeClass -> attachToClass -> attachCategories
上面支线我们已经跑通 下面来全局搜索 attachCategories 看哪里还用到了它经过我们的反推有了以下流程
load_images -> loadAllCategories -> load_categories_nolock -> attachCategories
示意图


截屏2020-10-22 下午6.29.28.png
  • realizeClassWithoutSwift 方法 (已知)
    懒加载类的时候 是 由 lookUpImpOrForward 发起的调用
    非懒加载类的时候 是由 map_images 发起的

  • attachCategories 方法

    1. 首先必要条件是研究的这个类存在分类(已知)
    2. attachToClass 是由realizeClassWithoutSwift掉起的 什么情况下才会掉起 attachCategories ?
    3. 既然 有懒加载类 和 非懒加载 区别 那么 分类是不是也有?
    4. 通过反推查看objc源码 得知 load_images 也可以掉起 attachCategories?什么时机掉起的?
  • 带着上面已知和未知的问题 就引出了下面要讲解的 类 和 分类搭配到的加载

类和分类搭配加载

首先配置环境主类 LGPerson

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface LGPerson : NSObject
@property (nonatomic, copy) NSString *kc_name;
@property (nonatomic, assign) int kc_age;
- (void)kc_instanceMethod1;
- (void)kc_instanceMethod3;
- (void)kc_instanceMethod2;
+ (void)kc_sayClassMethod;
@end

NS_ASSUME_NONNULL_END

#import "LGPerson.h"
@implementation LGPerson
+ (void)load{
    
}

- (void)kc_instanceMethod3{
    NSLog(@"%s",__func__);
}

- (void)kc_instanceMethod1{
    NSLog(@"%s",__func__);
}

- (void)kc_instanceMethod2{
    NSLog(@"%s",__func__);
}
+ (void)kc_sayClassMethod{
    NSLog(@"%s",__func__);
}
@end

分类1 LGPerson+LGA

#import "LGPerson.h"
NS_ASSUME_NONNULL_BEGIN
@interface LGPerson (LGA)
- (void)cateA_1;
- (void)cateA_2;
- (void)cateA_3;
@end
NS_ASSUME_NONNULL_END
#import "LGPerson+LGA.h"
@implementation LGPerson (LGA)
+ (void)load{
    
}
- (void)kc_instanceMethod1{
    NSLog(@"%s",__func__);
}
- (void)cateA_2{
    NSLog(@"%s",__func__);
}
- (void)cateA_1{
    NSLog(@"%s",__func__);
}
- (void)cateA_3{
    NSLog(@"%s",__func__);
}
@end

分类2 LGPerson+LGB

#import "LGPerson.h"

NS_ASSUME_NONNULL_BEGIN

@interface LGPerson (LGB)
- (void)cateB_1;
- (void)cateB_2;
- (void)cateB_3;
@end

NS_ASSUME_NONNULL_EN
#import "LGPerson+LGB.h"

@implementation LGPerson (LGB)
+ (void)load{
    
}

- (void)kc_instanceMethod1{
    NSLog(@"%s",__func__);
}

- (void)cateB_2{
    NSLog(@"%s",__func__);
}
- (void)cateB_1{
    NSLog(@"%s",__func__);
}
- (void)cateB_3{
    NSLog(@"%s",__func__);
}

@end

1.非懒加载类 + 非懒加载分类

  • 首先 在 realizeClassWithoutSwift 写下针对性研究LGPerson类的代码 并在里断点 看其调用堆栈


    截屏2020-10-23 下午12.56.46.png
  • 继续 在methodizeClass 写下针对性代码 并在里断点 看其调用堆栈


    截屏2020-10-23 下午1.03.22.png
  • 继续 在attachToClass 写下针对性代码 并在里断点 看其调用堆栈
截屏2020-10-23 下午1.09.56.png
  • 在下面打上新的断点 并 在 attachCategories里到打下断点


    截屏2020-10-23 下午1.18.36.png

    截屏2020-10-23 下午1.20.39.png

    过断点 发现 上面我们标红区域并没有走 但是确实也来到了 attachCategories方法 确实也是LGPerson 我们仔细看堆栈情况


    截屏2020-10-23 下午1.26.31.png

    (1). 此时发现 map_image掉起的流程已经结束 并没有调用 attachCategories。流程: map_image -> _read_images() -> realizeClassWithoutSwift -> methodizeClass ->attachToClass ->结束
    (2).而是由 load_image发起的调用流程:load_image -> loadAllCategories ->load_categories_nolock -> attachCategories
    (3).此时 rwe 有了值 我们bt 打印其 methods 发现其正是 对 ro->methods的数据拷贝 对于extAllocifNeeded()我们上面 也已经详细分析过了。

在下面继续断点跟踪


截屏2020-10-23 下午2.07.18.png

1.发现 cats_count =1 此时循环一次 分类的名字 为LGA 将分类中的方法 存入mists 的最后一位 上面有对此详细的解答

  1. 将分类的方法 进行排序 并将 分类的方法存入到 rwe中 通过 attachLists方法 上面我们也有对attachLists算法的详细解答

我们断过上面 来到 1399 1400 方法 并将 1367 和1399 1400 断点取消


截屏2020-10-23 下午2.21.37.png

继续过断点操作 发现此时断点又断回了attachCategories 中的针对性代码区域


截屏2020-10-23 下午2.25.40.png

继续打开 1367 1399 1400 向下走
截屏2020-10-23 下午2.30.11.png

1.发现 cats_count =1 此时循环一次 分类的名字 为LGB 将分类中的方法 存入mists 的最后一位

  1. 将分类的方法 进行排序 并将 分类的方法存入到 rwe中 通过 attachLists方法

继续取消 1367 和1399 1400 断点 向下走 发现又回到了 realizeClassWithoutSwift


截屏2020-10-23 下午2.42.20.png

断点到针对性代码下面


截屏2020-10-23 下午2.46.18.png

继续过断点 发现再此处 cls->isRealized() 判断了一下是否实现 实现返回cls 并没有向下执行 又回到了 realizeClassWithoutSwift方法对性代码里


截屏2020-10-23 下午2.49.29.png

继续过断点 从判断 cls->isRealized() 直接返回cls 整个流程跑完了程序进入了main函数
截屏2020-10-23 下午2.53.34.png

注:删掉其他断点留下针对性调试的断点 我们下面还会用哦
总结:非懒加载类+ 非懒加载分类 : 首先map_image -> _read_images() -> realizeClassWithoutSwift -> methodizeClass ->attachToClass ->结束
在这条支线上并未对 分类进行什么操作 只是完成了类的加载
然后发起 load_image函数的回调 -> loadAllCategories ->load_categories_nolock -> attachCategories (在这里有多次调用有几个非懒分类会调用几次)将分类的数据贴到 rwe中,并再次发起了 realizeClassWithoutSwift(有几个非懒分类会调用几次)的调用 来判断类是否已经实现。

2.非懒加载类 + 懒加载分类

  • 下面我们将源码中 所有分类的load都去掉 使分类变为懒加载概念 并运行 来到 realizeClassWithoutSwift 此时是由 map_images发起的调用


    截屏2020-10-23 下午3.49.37.png
  • 继续过断点 来到methodizeClass


    截屏2020-10-23 下午3.51.04.png
  • 继续过断点 来到attachToClass


    截屏2020-10-23 下午3.54.36.png
  • 将下面断点打开 并运行 发现并没有调用 attachCategories 中断


    截屏2020-10-23 下午3.58.46.png

    总结: 非懒加载类 + 懒加载分类 map_image -> _read_images() -> realizeClassWithoutSwift -> methodizeClass ->attachToClass ->结束

3.懒加载类 + 懒加载分类

  • 下面将主类和分类里所有的load方法全部去掉 使其变为所谓的懒加载 运行 来到 realizeClassWithoutSwift


    截屏2020-10-23 下午4.04.30.png

    发现此时的 realizeClassWithoutSwift 是由消息慢速查找流程里的lookUpImpOrForward掉起的。这说明在第一次消息 调用时候加载数据

  • 我们继续向下走 来到methodizeClass 方法


    截屏2020-10-23 下午4.11.13.png
  • 继续向下走 来到attachToClass 方法


    截屏2020-10-23 下午4.12.39.png
  • 打开下图所示断点 看是否可以进去调用 attachCategories


    截屏2020-10-23 下午4.14.27.png
  • 发现并未进去 此时运行完毕

总结流程: lookUpImpOrForward -> realizeClassMaybeSwiftMaybeRelock ->realizeClassWithoutSwift->methodizeClass->走完

4.懒加载类 + 非懒加载分类 (经测试 一个类拥有多个分类的情况下只要有大于等于两个分类实现load就会走下面流程)

  • 下面将主类去掉 load ,分类全部加上load 我们再次分析
    运行发现奔溃 去掉 针对性代码的元类判断 我们根据断点打印查看当前是否为 LGPerson


    截屏2020-10-23 下午4.27.26.png
  • 继续运行 来到 realizeClassWithoutSwift


    截屏2020-10-23 下午4.29.32.png

    我们看调用栈 realizeClassWithoutSwift 是由 load_images发起的

  • 继续运行来到 methodizeClass


    截屏2020-10-23 下午4.34.27.png
  • 继续运行来到 attachToClass


    截屏2020-10-23 下午4.36.45.png
  • 打开下面断点看其是否可以进去


    截屏2020-10-23 下午4.38.22.png
  • 继续运行 它进来了


    截屏2020-10-23 下午4.39.34.png

*继续过断点 来到了 attachCategories


截屏2020-10-23 下午4.40.52.png
  • 继续向下走


    截屏2020-10-23 下午4.43.31.png

    (1) .此时 cats_count = 2 因为两个分类 (还记得 非懒加载类+非懒加载分类 时 cats_count是=1 而是 调用了两遍 attachCategories方法,也就是 调用一次 初始化一个64位的栈 并将方法 分类方法存入此64位的最后一位)
    (2) .此时 for循环2遍 拿到 两个分类的 mlist 存入 mlists[64 - ++mcount ] 先进来的放在最后面 第二次进来的放在倒数第二未
    (3).分类方法排序prepareMethodLists
    (4). 通过attachLists方法 将mlists插入 rwe的方法列表

总结

  1. 懒加载类 + 非懒加载分类 调用 load_image函数的回调 -> prepare_load_methods ->realizeClassWithoutSwift ->methodizeClass -> attachToClass -> 并进入到 分类附加方法里 调用->attachCategories -> for循环 分类个数次数 ; 分类方法mlist 存入 mlists[64 - ++mcount ] 先进来的放在最后面 第二次进来的放在倒数第二 -> 1.将mlists方法 序列化 ;2.通过attachLists算法将 分类的方法 贴到rwe之中 -> realizeClassWithoutSwift 判断是否实现了cls实现返回 进入 main函数

懒加载类 + 非懒加载分类 + 懒加载分类(这种情况多个分类的情况下 有且只有一个分类为非懒加载才会走下面)

这种情况当由主类没有实现load 分类 两个其中的一个实现load 另一个不实现

  • 运行发现断到realizeClassWithoutSwift是由 map_images掉起的


    截屏2020-10-23 下午5.23.48.png
  • 过断点来到 methodizeClass


    截屏2020-10-23 下午5.26.35.png
  • 过断点来到 attachToClass


    截屏2020-10-23 下午5.27.29.png
  • 继续向下过断点 看是否会进入到下边


    截屏2020-10-23 下午5.28.41.png

*继续向下过断点 发现并未进入到 下方 attachCategories 取消断点继续运行 进入到了main

截屏2020-10-23 下午5.32.53.png

总结:懒加载类 + 非懒加载分类 + 懒加载分类 流程 map_images -> realizeClassWithoutSwift -> methodizeClass -> attachToClass ->进入main并未发现 attachCategories的调用

最后总结

我们将这几种情况的调用流程拿出来
1.非懒加载类 + 非懒加载分类
map_image -> _read_images() -> realizeClassWithoutSwift -> methodizeClass
load_image -> loadAllCategories ->load_categories_nolock -> attachCategories
2.非懒加载类 + 懒加载分类
map_image -> _read_images() -> realizeClassWithoutSwift -> methodizeClass
3.懒加载类 + 懒加载分类
lookUpImpOrForward -> realizeClassMaybeSwiftMaybeRelock ->realizeClassWithoutSwift->methodizeClass
4.懒加载类 + 非懒加载分类(多个分类大于等于两个实现load流程)
load_image -> prepare_load_methods ->realizeClassWithoutSwift ->methodizeClass -> attachToClass ->attachCategories
5.懒加载类 + 非懒加载分类 + 懒加载分类(多个分类有且只有一个分类实现load)
map_images ->_read_images()-> realizeClassWithoutSwift -> methodizeClass

可见load的非必须不要随意用 ,因为 在main函数之前会做很多很多事情。


截屏2020-10-23 下午5.43.43.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342