還沒搞懂JVM嘶窄?阿里資深架構(gòu)師一篇文章帶你深入淺出JVM怀跛!

本文跟大家聊聊JVM的內(nèi)部結(jié)構(gòu),從組件中的多線程處理柄冲,JVM系統(tǒng)線程吻谋,局部變量數(shù)組等方面進行解析

JVM

JVM = 類加載器(classloader) + 執(zhí)行引擎(execution engine) + 運行時數(shù)據(jù)區(qū)域(runtime data area)

下面這幅圖展示了一個典型的JVM(符合JVM Specification Java SE 7 Edition)所具備的關(guān)鍵內(nèi)部組件。

組件中的多線程處理

多線程處理”或“自由線程處理”指的是一個程序同時執(zhí)行多個操作線程的能力现横。 作為多線程應(yīng)用程序的一個示例漓拾,某個程序在一個線程上接收用戶輸入,在另一個線程上執(zhí)行多種復(fù)雜的計算戒祠,并在第三個線程上更新數(shù)據(jù)庫骇两。 在單線程應(yīng)用程序中,用戶可能會花費時間等待計算或數(shù)據(jù)庫更新完成姜盈。 而在多線程應(yīng)用程序中低千,這些進程可以在后臺進行,因此不會浪費用戶時間馏颂。 多線程處理可以是組件編程中的一個非常強大的工具示血。通過編寫多線程組件,您可以創(chuàng)建在后臺執(zhí)行復(fù)雜計算的組件救拉,它們允許用戶界面 (UI) 在計算的過程中自由地響應(yīng)用戶輸入难审。 雖然多線程處理是一個強大的工具,但是要將其正確應(yīng)用卻比較困難亿絮。 未能正確實現(xiàn)的多線程代碼可能降低應(yīng)用程序性能告喊,或甚至導(dǎo)致應(yīng)用程序凍結(jié)。 下列主題將向您介紹多線程編程的一些注意事項和最佳做法壹无。.NET Framework 提供幾個在組件中進行多線程處理的選項葱绒。 System.Threading 命名空間中的功能是一個選項。 基于事件的異步模式是另一個選項斗锭。 BackgroundWorker 組件是對異步模式的實現(xiàn)地淀;它提供封裝在組件中以便于使用的高級功能。

JVM內(nèi)存管理機制

(1)內(nèi)存區(qū)域與內(nèi)存溢出異常

(2)垃圾收集器與內(nèi)存分配策略

(3)虛擬機性能監(jiān)控與故障處理工具

JVM調(diào)優(yōu)

1.JVM執(zhí)行子系統(tǒng)

(1)類文件結(jié)構(gòu)

(2)類加載機制

(3)字節(jié)碼執(zhí)行引擎

2.程序編譯與代碼優(yōu)化

(1)編譯期優(yōu)化

(2)運行期優(yōu)化

3.實戰(zhàn)調(diào)優(yōu)案例與解決方法

JVM系統(tǒng)線程

如果你用jconsole或者任何其他的debug工具查看岖是,可能會看到有許多線程在后臺運行帮毁。這些運行著的后臺線程不包含主線程实苞,主線程是基于執(zhí)行publicstatic void main(String[]) 的需要而被創(chuàng)建的。而這些后臺線程都是被主線程所創(chuàng)建烈疚。在HotspotJVM中主要的后臺系統(tǒng)線程黔牵,見下表:

單個線程

每個線程的一次執(zhí)行都包含如下的組件

程序計數(shù)器(PC)

除非當前指令或者操作碼是原生的,否則當前指令或操作碼的地址都需要依賴于PC來尋址爷肝。如果當前方法是原生的猾浦,那么該PC即為undefined。所有的CPU都有一個PC灯抛,通常PC在每個指令執(zhí)行后被增加以指向即將執(zhí)行的下一條指令的地址金赦。JVM使用PC來跟蹤正在執(zhí)行的指令的位置。事實上对嚼,PC被用來指向methodarea的一個內(nèi)存地址夹抗。

原生棧

不是所有的JVM都支持原生方法,但那些支持該特性的JVM通常會對每個線程創(chuàng)建一個原生方法棧纵竖。如果對JVM的JNI(JavaNative Invocation)采用c鏈接模型的實現(xiàn)漠烧,那么原生棧也將是一個C實現(xiàn)的棧。在這個例子中靡砌,原生棧中參數(shù)的順序 已脓、返回值都將跟通常的C程序相同。一個原生方法通常會對JVM產(chǎn)生一個回調(diào)(這依賴于JVM的實現(xiàn))并執(zhí)行一個Java方法乏奥。這樣一個原生到Java的調(diào)用發(fā)生在棧上(通常在Java棧)摆舟,與此同時線程也將離開原生棧,通常在Java棧上創(chuàng)建一個新的frame。

每個線程都有屬于它自己的棧,用于存儲在線程上執(zhí)行的每個方法的frame炕舵。棧是一個后進先出的數(shù)據(jù)結(jié)構(gòu)恰起,這可以使得當前正在執(zhí)行的方法位于棧的頂部。對于每個方法的執(zhí)行,都會有一個新的frame被創(chuàng)建并被入棧到棧的頂部。當方法正常的返回或在方法執(zhí)行的過程中遇到未捕獲的異常時frame會被出棧。棧不會被直接進行操作厕鹃,除了push/ pop frame 對象。因此可以看出乍丈,frame對象可能會被分配在堆上剂碴,并且內(nèi)存也沒必要是連續(xù)的地址空間(請注意區(qū)分frame的指針跟frame對象)。

棧的限制

一個椙嶙ǎ可以是動態(tài)的或者是有合適大小的忆矛。如果一個線程要求更大的棧,那么將拋出StackOverflowError異常请垛;如果一個線程要求新創(chuàng)建一個frame催训,又沒有足夠的內(nèi)存空間來分配洽议,將會拋出OutOfMemoryError異常。

Frame

對于每一個方法的執(zhí)行漫拭,一個新frame會被創(chuàng)建并被入棧到棧頂亚兄。當方法正常返回或在方法執(zhí)行的過程中遇到未捕獲的異常,frame會被出棧采驻。

局部變量數(shù)組

局部變量數(shù)組包含了在方法執(zhí)行期間所用到的所有的變量审胚。包含一個對this的引用,所有的方法參數(shù)挑宠,以及其他局部定義的變量菲盾。對于類方法(比如靜態(tài)方法)颓影,方法參數(shù)的存儲索引從0開始各淀;而對于實例方法,索引為0的槽都為存儲this指針而保留诡挂。

操作數(shù)棧

操作數(shù)棧在字節(jié)碼指令被執(zhí)行的過程中使用碎浇。它跟原生CPU使用的通用目的的寄存器類似。大部分的字節(jié)碼都把時間花費在跟操作數(shù)棧打交道上璃俗,通過入棧奴璃、出棧、復(fù)制城豁、交換或者執(zhí)行那些生產(chǎn)/消費值的操作苟穆。對字節(jié)碼而言,那些在局部變量數(shù)組和操作數(shù)棧之間移動值的指令是非常頻繁的唱星。

動態(tài)鏈接

每個frame都包含一個對運行時常量池的引用雳旅。該引用指向?qū)⒁粓?zhí)行的方法所屬的類的常量池。該引用也用于輔助動態(tài)鏈接间聊。

當一個Java類被編譯時攒盈,所有對存儲在類的常量池中的變量以及方法的引用都被當做符號引用。一個符號引用僅僅只是一個邏輯引用而不是最終指向物理內(nèi)存地址的引用哎榴。JVM的實現(xiàn)可以選擇解析符號引用的時機型豁,該時機可以發(fā)生在當類文件被驗證后、被加載后尚蝌,這稱之eager或靜態(tài)分析迎变;不同的是它也可以發(fā)生在當符號引用被首次使用的時候,稱之為lazy或延遲分析飘言。但JVM必須保證:解析發(fā)生在每個引用被首次使用前衣形,同時在該時間點,如果遇到分析錯誤能夠拋出異常热凹。綁定是一個處理過程泵喘,它將被符號引用標識的字段泪电、方法或類替換為一個直接引用。這個處理過程只發(fā)生一次纪铺,因為符號引用需要被完全替換相速。如果一個符號引用關(guān)聯(lián)著一個類,而該類還沒有被解析鲜锚,那么該類也會被立即加載突诬。每個直接引用都被以偏移的方式存儲,該存儲結(jié)構(gòu)關(guān)聯(lián)著變量或方法的運行時位置芜繁。

線程之間共享

  • 堆中某個節(jié)點的值總是不大于或不小于其父節(jié)點的值旺隙;
  • 堆總是一棵完全二叉樹。

將根節(jié)點最大的堆叫做最大堆或大根堆骏令,根節(jié)點最小的堆叫做最小堆或小根堆蔬捷。常見的堆有二叉堆、斐波那契堆等榔袋。

堆的定義如下:n個元素的序列{k1,k2,ki,…,kn}當且僅當滿足下關(guān)系時周拐,稱之為堆。

(ki <= k2i,ki <= k2i+1)或者(ki >= k2i,ki >= k2i+1), (i = 1,2,3,4...n/2)

若將和此次序列對應(yīng)的一維數(shù)組(即以一維數(shù)組作此序列的存儲結(jié)構(gòu))看成是一個完全二叉樹凰兑,則堆的含義表明妥粟,完全二叉樹中所有非終端結(jié)點的值均不大于(或不小于)其左、右孩子結(jié)點的值吏够。由此勾给,若序列{k1,k2,…,kn}是堆,則堆頂元素(或完全二叉樹的根)必為序列中n個元素的最小值(或最大值)

非堆式內(nèi)存

有些對象并不會創(chuàng)建在堆中锅知,這些對象在邏輯上被認為是JVM機制的一部分播急。

非堆式的內(nèi)存包括:

  • 永久代中包含:
  • 方法區(qū)
  • 內(nèi)部字符串
  • 代碼緩存:用于編譯以及存儲方法,這些方法已經(jīng)被JIT編譯成本地代碼

內(nèi)存管理

對象和數(shù)組永遠都不會被顯式釋放喉镰,因此只能依靠垃圾回收器來自動地回收它們旅择。

通常,以如下的步驟進行:

  1. 新對象和數(shù)組被創(chuàng)建在年輕代
  2. 次垃圾回收器將在年輕代上執(zhí)行侣姆。那些仍然存活著的對象生真,將被從eden區(qū)移動到survivor區(qū)
  3. 主垃圾回收器將會把對象在代與代之間進行移動,主垃圾回收器通常會導(dǎo)致應(yīng)用程序的線程暫停捺宗。那些仍然存活著的對象將被從年輕代移動到老年代
  4. 永久代會在每次老年代被回收的時候同時進行柱蟀,它們在兩者中其一滿了之后都會被回收

JIT編譯

JIT具體的做法是這樣的:當載入一個類型時,CLR為該類型創(chuàng)建一個內(nèi)部數(shù)據(jù)結(jié)構(gòu)和相應(yīng)的函數(shù),當函數(shù)第一被調(diào)用時,JIT將該函數(shù)編譯成機器語言.當再次遇到該函數(shù)時則直接從cache中執(zhí)行已編譯好的機器語言.

方法區(qū)

所有的線程共享相同的方法區(qū)。所以蚜厉,對于方法區(qū)數(shù)據(jù)的訪問以及對動態(tài)鏈接的處理必須是線程安全的长已。如果兩個線程企圖訪問一個還沒有被載入的類(該類必須只能被加載一次)的字段或者方法,直到該類被加載完成,這兩個線程才能繼續(xù)執(zhí)行术瓮。

類的文件結(jié)構(gòu)

一個被編譯過的類文件包含如下的結(jié)構(gòu):

ClassFile
 { u4magic; u2minor_version; u2major_version; u2constant_pool_count; 
cp_infocontant_pool[constant_pool_count – 1]; u2access_flags; 
u2this_class; u2super_class; u2interfaces_count; 
u2interfaces[interfaces_count]; u2fields_count; 
field_infofields[fields_count]; u2methods_count; 
method_infomethods[methods_count]; u2attributes_count; 
attribute_infoattributes[attributes_count];}

可以使用javap命令查看被編譯后的java類的字節(jié)碼康聂。

下面列出了在該類文件中,使用到的操作碼:

就像在其他通用的字節(jié)碼中那樣胞四,以上這些操作碼主要用于跟本地變量恬汁、操作數(shù)棧以及運行時常量池打交道。

構(gòu)造器有兩個指令辜伟,第一個將“this”壓入到操作數(shù)棧氓侧,接下來該構(gòu)造器的父構(gòu)造器被執(zhí)行,這一操作將導(dǎo)致this被“消費”导狡,因此this將從操作數(shù)棧出棧约巷。

而對于sayHello()方法,它的執(zhí)行將更為復(fù)雜旱捧。因為它不得不通過運行時常量池独郎,解析符號引用到真實的引用。第一個操作數(shù)getstatic廊佩,用來入棧一個指向System類的靜態(tài)字段out的引用到操作數(shù)棧囚聚。接下來的操作數(shù)ldc,入棧一個字符串字面量“Hello”到操作數(shù)棧标锄。最后,invokevirtual操作數(shù)茁计,執(zhí)行System.out的println方法料皇,這將使得“Hello”作為一個參數(shù)從操作數(shù)棧出棧,并為當前線程創(chuàng)建一個新的frame星压。

類加載器

JVM的啟動是通過bootstrap類加載器來加載一個用于初始化的類践剂。在publicstatic void main(String[])被執(zhí)行前,該類會被鏈接以及實例化娜膘。main方法的執(zhí)行逊脯,將順序經(jīng)歷加載,鏈接竣贪,以及對額外必要的類跟接口的初始化军洼。

加載: 加載是這樣一個過程:查找表示該類或接口類型的類文件,并把它讀到一個字節(jié)數(shù)組中演怎。接著匕争,這些字節(jié)會被解析以確認它們是否表示一個Class對象以及是否有正確的主、次版本號爷耀。任何被當做直接superclass的類或接口也一同被加載甘桑。一旦這些工作完成,一個類或接口對象將會從二進制表示中創(chuàng)建。

鏈接: 鏈接包含了對該類或接口的驗證跑杭,準備類型以及該類的直接父類跟父接口铆帽。簡而言之,鏈接包含三個步驟:驗證德谅、準備以及解析(optional)

驗證:該階段會確認類以及接口的表示形式在結(jié)構(gòu)上的正確性锄贼,同時滿足Java編程語言以及JVM語義上的要求。

在驗證階段執(zhí)行這些檢查意味著在運行時可以免去在鏈接階段進行這些動作女阀,雖然拖慢了類的加載速度宅荤,然而它避免了在執(zhí)行字節(jié)碼的時候執(zhí)行這些檢查。

準備:包含了對靜態(tài)存儲的內(nèi)存分配以及JVM所使用的任何數(shù)據(jù)結(jié)構(gòu)(比如方法表)浸策。靜態(tài)字段都被創(chuàng)建以及實例化為它們的默認值冯键。然而,沒有任何實例化器或代碼在這個階段被執(zhí)行庸汗,因為這些任務(wù)將會發(fā)生在實例化階段惫确。

解析:是一個可選的階段。該階段通過加載引用的類或接口來檢查符號引用是否正確蚯舱。如果在這個點這些檢查沒發(fā)生改化,那么對符號引用的解析會被推遲到直到它們被字節(jié)碼指令使用之前。

實例化 類或接口枉昏,包含執(zhí)行類或接口的實例化方法:<clinit>

在JVM中存在多個不同職責(zé)的類加載器陈肛。每一個類加載器都代理其已被加載的父加載器(除了bootstrap類加載器,因為它是根加載器)兄裂。

Bootstrap類加載器:當java程序運行時句旱,java虛擬機需要裝載java類,這個過程需要一個類裝載器來完成晰奖。而類裝載器本身也是一個java類谈撒,這就出現(xiàn)了類似人類的第一位母親是如何產(chǎn)生出來的問題。

其實匾南,java虛擬機中內(nèi)嵌了一個稱為Bootstrap的類裝載器啃匿,它是用特定于操作系統(tǒng)的本地代碼實現(xiàn)的,屬于java虛擬機的內(nèi)核蛆楞,這個Bootstrap類裝載器不用專門的類裝載器去裝載溯乒。Bootstrap類裝載器負責(zé)加載java核心包中的類。

Extension 類加載器:從標準的Java擴展API中加載類臊岸。例如橙数,安全的擴展功能集。

System 類加載器:這是應(yīng)用程序默認的類加載器帅戒。它從classpath中加載應(yīng)用程序類灯帮。

用戶定義的類加載器:可以額外得定義類加載器來加載應(yīng)用程序類崖技。用戶定義的類加載器可用于一些特殊的場景,比如:在運行時重新加載類或?qū)⒁恍┨厥獾念惛綦x為多個不同的分組(通常web服務(wù)器中都會有這樣的需求钟哥,比如Tomcat)迎献。

更快的類加載

一個稱之為類數(shù)據(jù)共享(CDS)的特性自HotspotJVM 5.0開始被引進。在安裝JVM期間腻贰,安裝器加載一系列的Java核心類(如rt.jar)到一個經(jīng)過映射過的內(nèi)存區(qū)進行共享存檔吁恍。CDS減少了加載這些類的時間從而提升了JVM的啟動速度,同時允許這些類在不同的JVM實例之間共享播演。這大大減少了內(nèi)存碎片冀瓦。

方法區(qū)的位置

JVM Specification Java SE 7 Edition清楚地聲明:盡管方法區(qū)是堆的一個邏輯組成部分,但最簡單的實現(xiàn)可能是既不對它進行垃圾回收也不壓縮它写烤。然而矛盾的是利用jconsole查看Oracle的JVM的方法區(qū)(以及CodeCache)是非堆形式的翼闽。OpenJDK代碼顯示CodeCache相對ObjectHeap而言是VM中一個獨立的域。

類加載器引用

類通常是按需加載洲炊,即第一次使用該類時才加載感局。由于有了類加載器,Java運行時系統(tǒng)不需要知道文件與文件系統(tǒng)暂衡。

運行時常量池

JVM對每個類型維護著一個常量池询微,它是一個跟符號表相似的運行時數(shù)據(jù)結(jié)構(gòu),但它包含了更多的數(shù)據(jù)狂巢。Java的字節(jié)碼需要一些數(shù)據(jù)撑毛,通常這些數(shù)據(jù)會因為太大而難以直接存儲在字節(jié)碼中。取而代之的一種做法是將其存儲在常量池中隧膘,字節(jié)碼包含一個對常量池的引用代态。運行時常量池主要用來進行動態(tài)鏈接。

幾種類型的數(shù)據(jù)會存儲在常量池中疹吃,它們是:

  • 數(shù)值字面量
  • 字符串字面量
  • 類的引用
  • 字段的引用
  • 方法的引用

如果你編譯下面的這個簡單的類:

package org.jvminternals;public class SimpleClass { public void sayHello() {System.out.println("Hello");}}

生成的類文件的常量池,看起來會像下圖所示:

Constant
 pool: #1 = Methodref #6.#17 // java/lang/Object."<init>":()V#2 = 
Fieldref #18.#19 // java/lang/System.out:Ljava/io/PrintStream;#3 = 
String #20 // "Hello"#4 = Methodref #21.#22 // 
java/io/PrintStream.println:(Ljava/lang/String;)V#5 = Class #23 // 
org/jvminternals/SimpleClass#6 = Class #24 // java/lang/Object#7 = Utf8 
<init> #8 = Utf8 ()V #9 = Utf8 Code #10 = Utf8 LineNumberTable #11
 = Utf8 LocalVariableTable #12 = Utf8 this #13 = Utf8 
Lorg/jvminternals/SimpleClass; #14 = Utf8 sayHello #15 = Utf8 SourceFile
 #16 = Utf8 SimpleClass.java #17 = NameAndType #7:#8 // 
"<init>":()V#18 = Class #25 // java/lang/System#19 = NameAndType 
#26:#27 // out:Ljava/io/PrintStream;#20 = Utf8 Hello #21 = Class #28 // 
java/io/PrintStream#22 = NameAndType #29:#30 // 
println:(Ljava/lang/String;)V#23 = Utf8 org/jvminternals/SimpleClass #24
 = Utf8 java/lang/Object#25 = Utf8 java/lang/System #26 = Utf8 out#27 = 
Utf8 Ljava/io/PrintStream; #28 = Utf8 java/io/PrintStream #29 = Utf8 
println #30 = Utf8 (Ljava/lang/String;)V

常量池中包含了下面的這些類型:

異常表

異常表存儲了每個異常處理器的信息:

  • 起始點
  • 終止點
  • 處理代碼的PC偏移量
  • 被捕獲的異常類的常量池索引

如果一個方法定義了try-catch或try-finally異常處理器西雀,那么一個異常表將會被創(chuàng)建萨驶。它包含了每個異常處理器的信息或者finally塊以及正在被處理的異常類型跟處理器代碼的位置。

當一個異常被拋出艇肴,JVM會為當前方法尋找一個匹配的處理器腔呜。如果沒有找到,那么該方法最終會唐突地出棧當前stackframe而異常會被重新拋出到調(diào)用鏈(新的frame)再悼。如果在所有的frame都出棧之前還是沒有找到異常處理器核畴,那么當前線程將會被終止。當然這也可能會導(dǎo)致JVM被終止冲九,如果異常被拋出到最后一個非后臺線程的話谤草,比如該線程就是主線程跟束。

最終異常處理器會匹配所有的異常類型并且無論什么時候該類型的異常被拋出總是會得到執(zhí)行。在沒有異常拋出的例子中丑孩,finally塊仍然會在方法的最后被執(zhí)行冀宴。一旦return語句被執(zhí)行就會立即跳轉(zhuǎn)到finally代碼塊繼續(xù)執(zhí)行。

字符比較

字符比較(character comparison)是指按照字典次序?qū)蝹€字符或字符串進行比較大小的操作温学,一般都是以ASCII碼值的大小作為字符比較的標準略贮。

符號表

符號表在編譯程序工作的過程中需要不斷收集、記錄和使用源程序中一些語法符號的類型和特征等相關(guān)信息仗岖。這些信息一般以表格形式存儲于系統(tǒng)中逃延。如常數(shù)表、變量名表轧拄、數(shù)組名表揽祥、過程名表、標號表等等紧帕,統(tǒng)稱為符號表盔然。對于符號表組織、構(gòu)造和管理方法的好壞會直接影響編譯系統(tǒng)的運行效率是嗜。

在JVM中愈案,內(nèi)部字符串被存儲在字符串表中。字符串表是一個hashtable映射對象指針到符號(比如:Hashtable<oop,Symbol>)鹅搪,它被存儲在永久代里站绪。

當類被加載時,字符串字面量會被編譯器自動“內(nèi)部化”并且被加入到字符表丽柿。另外字符串類的實例可以通過調(diào)用String.intern()來明確地內(nèi)部化恢准。當String.intern()被調(diào)用,如果符號表里已經(jīng)包含該字符串甫题,那么指向該字符串的引用將被返回馁筐。如果該字符串沒有包含在字符表,則會被加入到字符串表同時返回其引用

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末坠非,一起剝皮案震驚了整個濱河市敏沉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌炎码,老刑警劉巖盟迟,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異潦闲,居然都是意外死亡攒菠,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進店門歉闰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辖众,“玉大人卓起,你說我怎么就攤上這事≌栽” “怎么了既绩?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長还惠。 經(jīng)常有香客問我饲握,道長,這世上最難降的妖魔是什么蚕键? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任救欧,我火速辦了婚禮,結(jié)果婚禮上锣光,老公的妹妹穿的比我還像新娘笆怠。我一直安慰自己,他們只是感情好誊爹,可當我...
    茶點故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布蹬刷。 她就那樣靜靜地躺著,像睡著了一般频丘。 火紅的嫁衣襯著肌膚如雪办成。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天搂漠,我揣著相機與錄音迂卢,去河邊找鬼。 笑死桐汤,一個胖子當著我的面吹牛而克,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播怔毛,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼员萍,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了拣度?” 一聲冷哼從身側(cè)響起充活,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蜡娶,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體映穗,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡窖张,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了蚁滋。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宿接。...
    茶點故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡赘淮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出睦霎,到底是詐尸還是另有隱情梢卸,我是刑警寧澤,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布副女,位于F島的核電站蛤高,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏碑幅。R本人自食惡果不足惜戴陡,卻給世界環(huán)境...
    茶點故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望沟涨。 院中可真熱鬧恤批,春花似錦、人聲如沸裹赴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽棋返。三九已至延都,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間懊昨,已是汗流浹背窄潭。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留酵颁,地道東北人嫉你。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像躏惋,于是被迫代替她去往敵國和親幽污。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,941評論 2 355

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