JVM_字节码:字节码相关概述

Java字节码的整体结构:

整体结构1.png

整体结构2.png

整体结构3.png

Class字节码中有两种数据类型:

  • 字节码数据直接量:这是基本的数据类型,共细分为u1、u2、u4、u84种类型,分别代表连续的1个字节、2个字节、4个字节、8个字节组成的整体数据。

  • 表(数组):表是由多个基本数据或者其他表按照既定的顺序组成的大的数据集合,表是有结构的,它的结构体现在:组成表的成分所在的位置和顺序都是已经严格定义好的。


字节码的类型.png

上面的表描述了11种数据类型的结构,其实在JDK1.7之后,又增加了3种,
(CONSTANT_MethodHandle_info、CONSTANT_MethodType_info以及CONSTANT_InvokeDynamic_info)这样一共存在14种数据类型。


Access_Flag访问标志:
访问标志信息包括Class文件是类还是接口,是否被定义成public,是否是abstract,如果是类,是否被声明为final。

修饰符的表:


修饰符常量表

Tips: 少了一个0x0002表示的是ACC_PRIVATE

0x0021: 是0x0001和0x0020的并集,表示的是ACC_PUBLIC和ACC_SUPER
00 21 // 表示的是ACCESS_FLAG 修饰符A&修饰符B&... ACC_PUBLIC(0x0001)&ACC_SUPER(0x0020)
00 03 // 当前类的全局限定名称指向常量池 #3 = Class #22 // com/compass/spring_lecture/binarycode/MyTest1
00 04 //表示当前类的父类全局限定名称指向常量池 #4 = Class #23 // java/lang/Object
00 00 //表示接口的数量
00 01 //表示字段的数量 1


字段表的集合:
字段表用于描述类和接口中声明的变量,这里的字段包括类级别的变量及实例变量,但是不包括方法内部声明的局部变量。
字段表结构:


表结构1

表结构2.png

方法表的集合:


表结构1

表结构2

方法表的属性结构:

  • JVM预定义了部分的attribute,但是编译器自己也可以实现自己的attribute并写入到class文件中,供运行时使用。
  • 不同的attribute是通过attribute_name_index来区分的。

JVM规范预定义的属性:


JVM规范预定义的属性

方法中的每个属性都是一个atrribute_info结构:


atrribute_info结构

Code结构:
Code attribute的作用是保存该方法的结构,如所对应的字节码结构:


Code attribute对应的字节码结构

Code结构:

  • attribute_length表示attribute所包含的字节数,不包含arribute_name_index和attribute_length字段。
  • max_stack表示这个方法运行的任何时刻所能达到的操作数栈的最大深度
  • max_locals表示方法执行期间创建的局部变量的数目,包含用来表示传入的参数的局部变量
  • code_length: 表示该方法所包含的字节码的字节数以及具体的指令码
  • 具体字节码即是该方法被调用时,虚拟机所执行的代码
  • exception_table,这里存放的是处理异常的信息
  • 每个exception_table表项由start_pc、end_pc、handler_pc、catch_type组成
  • start_pc和end_pc 表示在code数组中的从start_pc到end_pc处(包含start_pc不包含end_pc即([start_pc,end_pc)))的指令抛出异常会由这个表项来处理。
  • handler_pc 表示处理异常的代码的开始处,catch_type表示会被处理的异常类型,它指向常量池里的一个异常类。当catch_type为0时,表示处理所有的异常。
    完整的字节码如下:
Classfile /C:/spring_lecture/target/classes/com/compass/spring_lecture/binarycode/MyTest1.class
  Last modified 2019年6月26日; size 521 bytes
  MD5 checksum e84ac7b4ed245fd5824849fb69bacc27
  Compiled from "MyTest1.java"
public class com.compass.spring_lecture.binarycode.MyTest1
  minor version: 0 //小版本
  major version: 52 //大版本
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #3                          // com/compass/spring_lecture/binarycode/MyTest1
  super_class: #4                         // java/lang/Object
  interfaces: 0, fields: 1, methods: 3, attributes: 1
Constant pool://常量池
   #1 = Methodref          #4.#20         // java/lang/Object."<init>":()V
   #2 = Fieldref           #3.#21         // com/compass/spring_lecture/binarycode/MyTest1.a:I
   #3 = Class              #22            // com/compass/spring_lecture/binarycode/MyTest1
   #4 = Class              #23            // java/lang/Object
   #5 = Utf8               a
   #6 = Utf8               I
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lcom/compass/spring_lecture/binarycode/MyTest1;
  #14 = Utf8               getA
  #15 = Utf8               ()I
  #16 = Utf8               setA
  #17 = Utf8               (I)V
  #18 = Utf8               SourceFile
  #19 = Utf8               MyTest1.java
  #20 = NameAndType        #7:#8          // "<init>":()V
  #21 = NameAndType        #5:#6          // a:I
  #22 = Utf8               com/compass/spring_lecture/binarycode/MyTest1
  #23 = Utf8               java/lang/Object
{
  public com.compass.spring_lecture.binarycode.MyTest1();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
      ----------------------------------------------------------------
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: iconst_1
         6: putfield      #2                  // Field a:I
         9: return
      ----------------------------------------------------------------   
      LineNumberTable:
        line 4: 0
        line 6: 4
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      10     0  this   Lcom/compass/spring_lecture/binarycode/MyTest1;

  public int getA();
    descriptor: ()I
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
      ----------------------------------------------------------------
         0: aload_0
         1: getfield      #2                  // Field a:I
         4: ireturn
      LineNumberTable:
      ----------------------------------------------------------------
        line 10: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/compass/spring_lecture/binarycode/MyTest1;

  public void setA(int);
    descriptor: (I)V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=2, args_size=2
      ----------------------------------------------------------------
         0: aload_0
         1: iload_1
         2: putfield      #2                  // Field a:I
         5: return
      ----------------------------------------------------------------   
      LineNumberTable: //行号表
        line 14: 0
        line 15: 5
      LocalVariableTable: //局部变量表
        Start  Length  Slot  Name   Signature
            0       6     0  this   Lcom/compass/spring_lecture/binarycode/MyTest1;
            0       6     1     a   I
}
SourceFile: "MyTest1.java"

将常量池的字节码抽取出来如下:

Constant pool://常量池
   序号  类型               引用  
  
   #1 = Methodref          #4.#20         // java/lang/Object."<init>":()V
   #2 = Fieldref           #3.#21         // com/compass/spring_lecture/binarycode/MyTest1.a:I
  
   #3 = Class              #22            // com/compass/spring_lecture/binarycode/MyTest1
   #4 = Class              #23            // java/lang/Object
  
   #5 = Utf8               a
   #6 = Utf8               I
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lcom/compass/spring_lecture/binarycode/MyTest1;
  #14 = Utf8               getA
  #15 = Utf8               ()I
  #16 = Utf8               setA
  #17 = Utf8               (I)V
  #18 = Utf8               SourceFile
  #19 = Utf8               MyTest1.java


  #20 = NameAndType        #7:#8          // "<init>":()V
  #21 = NameAndType        #5:#6          // a:I
  
  #22 = Utf8               com/compass/spring_lecture/binarycode/MyTest1
  #23 = Utf8               java/lang/Object

字节码的16进制信息:

ca fe ba be 00 00 00 34 00 18 0a 00 04 00 14 09 
00 03 00 15 07 00 16 07 00 17 01 00 01 61 01 00 
01 49 01 00 06 3c 69 6e 69 74 3e 01 00 03 28 29 
56 01 00 04 43 6f 64 65 01 00 0f 4c 69 6e 65 4e 
75 6d 62 65 72 54 61 62 6c 65 01 00 12 4c 6f 63 
61 6c 56 61 72 69 61 62 6c 65 54 61 62 6c 65 01 
00 04 74 68 69 73 01 00 2f 4c 63 6f 6d 2f 63 6f 
6d 70 61 73 73 2f 73 70 72 69 6e 67 5f 6c 65 63 
74 75 72 65 2f 62 69 6e 61 72 79 63 6f 64 65 2f 
4d 79 54 65 73 74 31 3b 01 00 04 67 65 74 41 01 
00 03 28 29 49 01 00 04 73 65 74 41 01 00 04 28 
49 29 56 01 00 0a 53 6f 75 72 63 65 46 69 6c 65 
01 00 0c 4d 79 54 65 73 74 31 2e 6a 61 76 61 0c 
00 07 00 08 0c 00 05 00 06 01 00 2d 63 6f 6d 2f 
63 6f 6d 70 61 73 73 2f 73 70 72 69 6e 67 5f 6c 
65 63 74 75 72 65 2f 62 69 6e 61 72 79 63 6f 64 
65 2f 4d 79 54 65 73 74 31 01 00 10 6a 61 76 61 
2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 00 21 00 03 
00 04 00 00 00 01 00 02 00 05 00 06 00 00 00 03 
00 01 00 07 00 08 00 01 00 09 00 00 00 38 00 02 
00 01 00 00 00 0a 2a b7 00 01 2a 04 b5 00 02 b1 
00 00 00 02 00 0a 00 00 00 0a 00 02 00 00 00 04 
00 04 00 06 00 0b 00 00 00 0c 00 01 00 00 00 0a 
00 0c 00 0d 00 00 00 01 00 0e 00 0f 00 01 00 09 
00 00 00 2f 00 01 00 01 00 00 00 05 2a b4 00 02 
ac 00 00 00 02 00 0a 00 00 00 06 00 01 00 00 00 
0a 00 0b 00 00 00 0c 00 01 00 00 00 05 00 0c 00 
0d 00 00 00 01 00 10 00 11 00 01 00 09 00 00 00 
3e 00 02 00 02 00 00 00 06 2a 1b b5 00 02 b1 00 
00 00 02 00 0a 00 00 00 0a 00 02 00 00 00 0e 00 
05 00 0f 00 0b 00 00 00 16 00 02 00 00 00 06 00 
0c 00 0d 00 00 00 00 00 06 00 05 00 06 00 01 00 
01 00 12 00 00 00 02 00 13 

对上述的16进制编码进行分析:


ca fe ba be //魔数


00 00 00 34 //版本信息 00 00 (次版本号) 00 34(52主版本号)


00 18 //CONSTANT_POOL START 常量池数量信息 00 16 (24)
0a 00 04 00 14 09 00 03 00 15 07 00 16 07 00
17 01 00 01 61 01 00 01 49 01 00 06 3c 69 6e
69 74 3e 01 00 03 28 29 56 01 00 04 43 6f 64
65 01 00 0f 4c 69 6e 65 4e 75 6d 62 65 72 54
61 62 6c 65 01 00 12 4c 6f 63 61 6c 56 61 72
69 61 62 6c 65 54 61 62 6c 65 01 00 04 74 68
69 73 01 00 2f 4c 63 6f 6d 2f 63 6f 6d 70 61
73 73 2f 73 70 72 69 6e 67 5f 6c 65 63 74 75
72 65 2f 62 69 6e 61 72 79 63 6f 64 65 2f 4d
79 54 65 73 74 31 3b 01 00 04 67 65 74 41 01
00 03 28 29 49 01 00 04 73 65 74 41 01 00 04 28
49 29 56 01 00 0a 53 6f 75 72 63 65 46 69 6c 65
01 00 0c 4d 79 54 65 73 74 31 2e 6a 61 76 61 0c
00 07 00 08 0c 00 05 00 06 01 00 2d 63 6f 6d 2f
63 6f 6d 70 61 73 73 2f 73 70 72 69 6e 67 5f 6c
65 63 74 75 72 65 2f 62 69 6e 61 72 79 63 6f 64
65 2f 4d 79 54 65 73 74 31 01 00 10 6a 61 76 61
2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 //CONSTANT_POOL END


00 21 // 表示的是ACCESS_FLAG 修饰符A&修饰符B&... ACC_PUBLIC(0x0001)&ACC_SUPER(0x0020)


00 03 // 当前类的全局限定名称指向常量池 #3 = Class #22 //
com/compass/spring_lecture/binarycode/MyTest1


00 04 //表示当前类的父类全局限定名称指向常量池 #4 = Class #23 // java/lang/Object


00 00 //表示接口的数量


00 01 //表示字段的数量 1
00 02 //字段的描述符ACCESS_FLAG ACC_PRIVATE(0x0002)
00 05 //5 表示字段的名称 #5 = Utf8 a
00 06 //6 表示字段的描述符也就是类型 #6 = Utf8 I
00 00 //字段的属性个数0


00 03 //表示方法的数量 3
00 01 //方法的访问标记 ACC_PUBLIC(0x0001)
00 07 //方法名字索引 #7 = Utf8 <init>
00 08 //方法的描述符索引 #8 = Utf8 ()V
00 01 //方法中属性的个数 1 方法的属性是this args_size=1
00 09 //表示的是属性名的索引 #9 = Utf8 Code(表示代码片段 方法的执行代码)
00 00 00 38 //U4 表示属性的长度 38=16*3+8=48+8=56 表示attribute所包含的字节数,不包含arribute_name_index和attribute_length字段
00 02 //U2 表示 max_stack stack=2 表示这个方法运行的任何时刻所能达到的操作数栈的最大深度
00 01 //U2 表示 max_local locals=1 表示方法执行期间创建的局部变量的数目,包含用来表示传入的参数的局部变量
00 00 00 0a //表示的是code_length 10 //表示该方法所包含的字节码的字节数以及具体的指令码 具体字节码即是该方法被调用时,虚拟机所执行的代码
第6章 . JVM的机器执行指令集:
Chapter 6. The Java Virtual Machine Instruction Set :https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html

2a b7 00 01 2a 04 b5 00 02 b1 //这10个字节对应方法的执行代码 这里需要参考JVM的规范:
---
2a ---aload_0 = 42 (0x2a) 
Description:
The <n> must be an index into the local variable array of the current frame (§2.6). 
The local variable at <n> must contain a reference. The objectref in the local
variable at <n> is pushed onto the operand stack.
-------
b7 ---invokespecial = 183 (0xb7)
b7后面的2个字节
00 01 ---表示它接收的参数
Description:
调用了父类的构造器,详细信息见规范比较多
-------
2a ---aload_0 = 42 (0x2a) 
Description:
The <n> must be an index into the local variable array of the current frame (§2.6). 
The local variable at <n> must contain a reference. The objectref in the local
variable at <n> is pushed onto the operand stack.
-------
04 ---iconst_1 = 4 (0x4)
Description:
Push the int constant <i> (-1, 0, 1, 2, 3, 4 or 5) onto the operand stack.
-------
b5 ---putfield = 181 (0xb5)
Description:
给成员变量赋值
The unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class (§2.6), where the value of the index is (indexbyte1 << 8) | indexbyte2. The run-time constant pool item at that index must be a symbolic reference to a field (§5.1), which gives the name and descriptor of the field as well as a symbolic reference to the class in which the field is to be found. The class of objectref must not be an array. If the field is protected, and it is a member of a superclass of the current class, and the field is not declared in the same run-time package (§5.3) as the current class, then the class of objectref must be either the current class or a subclass of the current class.
The referenced field is resolved (§5.4.3.2). The type of a value stored by a putfield instruction must be compatible with the descriptor of the referenced field (§4.3.2). If the field descriptor type is boolean, byte, char, short, or int, then the value must be an int. If the field descriptor type is float, long, or double, then the value must be a float, long, or double, respectively. If the field descriptor type is a reference type, then the value must be of a type that is assignment compatible (JLS §5.2) with the field descriptor type. If the field is final, it must be declared in the current class, and the instruction must occur in an instance initialization method (<init>) of the current class (§2.9).
The value and objectref are popped from the operand stack. The objectref must be of type reference. The value undergoes value set conversion (§2.8.3), resulting in value', and the referenced field in objectref is set to value'.
-------
00 02 --- 表示putfield的参数
Description:
#2 = Fieldref           #3.#21         // com/compass/spring_lecture/binarycode/MyTest1.a:I
-------
b1 --- return = 177 (0xb1)  
Description:
The current method must have return type void. If the current method is a synchronized method, the monitor entered or reentered on invocation of the method is updated and possibly exited as if by execution of a monitorexit instruction (§monitorexit) in the current thread. If no exception is thrown, any values on the operand stack of the current frame (§2.6) are discarded.
The interpreter then returns control to the invoker of the method, reinstating the frame of the invoker.
-------

00 00 //表示这个方法的异常表
00 02 //表示这个方法存在2个属性(不是成员变量的概念 不要混淆)
附加属性:

  • 接下来就是方法的附加属性
  • LineNumberTable: 这个属性用来表示code数组中的字节码和Java代码行数之间的关系。这个属性可以用来在调试的时候定位代码执行的行数。


    LineNumberTable的结构

    00 0a //10---#10 = Utf8 LineNumberTable 行号表
    00 00 00 0a //10 行号表属性的长度


00 02 00 00 00 04 00 04 00 06 //行号信息 
00 02: 表示存在几对映射(10-2)/2=4 4个字节一个映射关系
00 00 00 04:字节码的偏移量0映射的行号为4
00 04 00 06:字节码的偏移量4映射的行号为6

可以对照jclasslib的结果来验证自己的分析结果:


image.png
-------
00 0b //表示局部变量表 11
00 00 00 0c //表示局部变量表的长度 12
00 01 //局部变量的个数 1
00 00 //表示局部变量的开始位置
00 0a //表示局部变量的结束位置
00 //索引是0
0c //对应常量池的位置 12 #12 = Utf8               this 是编译器默认作为方法的第1个参数传进来 ---成员方法
00 0d // 当前对象的描述符 #13 = Utf8               Lcom/compass/spring_lecture/binarycode/MyTest1;
00 00 // jdk 1.6 之后的javac 提供了StackMapTable 属性长度是1 用于校验
-------
00 01 //方法的访问标记 ACC_PUBLIC(0x0001)
00 0e //方法的名字索引 #14 = Utf8               getA
00 0f //方法的描述符索引  #15 = Utf8               ()I
00 01 //方法中属性的个数 1 方法的属性是this args_size=1
00 09  //表示的是属性名的索引 #9 = Utf8               Code(表示代码片段 方法的执行代码)
00 00 00 2f //U4 表示属性的长度 2f=16*2+15=47 表示attribute所包含的字节数,不包含arribute_name_index和attribute_length字段
00 01 //U2 表示 max_stack stack=1 表示这个方法运行的任何时刻所能达到的操作数栈的最大深度
00 01 //U2 表示 max_local locals=1 表示方法执行期间创建的局部变量的数目,包含用来表示传入的参数的局部变量
00 00 00 05 //U4  表示的是code_length 5 //表示该方法所包含的字节码的字节数以及具体的指令码 具体字节码即是该方法被调用时,虚拟机所执行的代码
-------

2a b4 00 02 ac //参考JVM Introductuion Set Specification
0 aload_0(0x2a)
1 getfield(0xb4) #2(0x 00 02) <com/compass/spring_lecture/binarycode/MyTest1.a>
4 ireturn(0xac)

00 00 //表示这个方法的异常表
00 02 //表示这个方法存在2个属性(不是成员变量的概念 不要混淆)
00 0a //10---#10 = Utf8               LineNumberTable 行号表
00 00 00 06 //6 行号表属性的长度
00 01 //表示存在几对映射(6-2)/1=4 表示4个字节一个映射
00 00 00 0a  // 字节码的偏移量映射0的行号为12
00 0b //表示局部变量表 11
00 00 00 0c //表示局部变量表的长度 12
00 01 //局部变量的个数 1
00 00 //表示局部变量的开始位置
00 05 //表示局部变量的结束位置
00 //索引是0
0c //对应常量池的位置 12 #12 = Utf8               this 是编译器默认作为方法的第1个参数传进来 ---成员方法
00 0d // 当前对象的描述 #13 = Utf8               Lcom/compass/spring_lecture/binarycode/MyTest1;
00 00 // jdk 1.6 之后的javac 提供了StackMapTable 属性长度是1 用于校验
-------
00 01 //方法的访问标记 ACC_PUBLIC(0x0001)
00 10 //#16 = Utf8               setA
00 11 //#17 = Utf8               (I)V
00 01 //方法中属性的个数 1 方法的属性是this args_size=1
00 09 //表示的是属性名的索引 #9 = Utf8               Code(表示代码片段 方法的执行代码)
00 00 00 3e//U4 表示属性的长度 3e=16*3+14=48+14=62 表示attribute所包含的字节数,不包含arribute_name_index和attribute_length字段
00 02 //U2 表示 max_stack stack=1 表示这个方法运行的任何时刻所能达到的操作数栈的最大深度
00 02 //U2 表示 max_stack stack=1 表示这个方法运行的任何时刻所能达到的操作数栈的最大深度
00 00 00 06 //U4  表示的是code_length 6 //表示该方法所包含的字节码的字节数以及具体的指令码 具体字节码即是该方法被调用时,虚拟机所执行的代码

2a 1b b5 00 02 b1
0 aload_0(0x2a)
1 iload_1(0x1b)
2 putfield (0xb5)#2(0x0002) <com/compass/spring_lecture/binarycode/MyTest1.a>
5 return(0xb1)

00 00 //表示这个方法的异常表
00 02 //表示这个方法存在2个属性(不是成员变量的概念 不要混淆)
00 0a //10---#10 = Utf8               LineNumberTable 行号表
00 00 00 0a //10 行号表属性的长度
00 02//表示存在几对映射(10-2)/1=4 表示4个字节一个映射 
00 00 00 0e//字节码的偏移量映射0的行号为14
00 05 00 0f //字节码的偏移量映射5的行号为15
00 0b////表示局部变量表 11
00 00 00 16//表示局部变量表的长度 22
----------------
00 02 //局部变量的个数 2
00 00 //表示局部变量的开始位置
00 06 //表示局部变量的结束位置
00 //索引是0
0c //对应常量池的位置 12 #12 = Utf8               this 是编译器默认作为方法的第1个参数传进来 ---成员方法
00 0d // 当前对象的描述符 #13 = Utf8               Lcom/compass/spring_lecture/binarycode/MyTest1;
00 00 //jdk 1.6 之后的javac 提供了StackMapTable 属性长度是1 用于校验
00 00 //起始位置是0
00 06 //结束位置是6
00 //索引是0
05    //#5 = Utf8               a  
00 06 // #6 = Utf8               I
00 01 //jdk 1.6 之后的javac 提供了StackMapTable 属性长度是1 用于校验

属性内容
00 01//一个属性
00 12//对应常量池的18 #18 = Utf8 SourceFile
00 00 00 02//长度是2 后面的两个字节
00 13//对应源文件


附加属性

  • 接下来就是方法的附加属性
  • LineNumberTable: 这个属性用来表示code数组中的字节码和Java代码行数之间的关系。这个属性可以用来在调试的时候定位代码执行的行数。


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

推荐阅读更多精彩内容