理解Android虛擬機(jī)體系結(jié)構(gòu)

本文轉(zhuǎn)載自https://www.cnblogs.com/lao-liang/p/5111399.html秕脓,如侵權(quán)必刪
歡迎關(guān)注博主:http://www.cnblogs.com/lao-liang/

1 什么是Dalvik虛擬機(jī)

Dalvik是Google公司自己設(shè)計(jì)用于Android平臺(tái)的Java虛擬機(jī)展东,它是Android平臺(tái)的重要組成部分呆馁,支持dex格式(Dalvik Executable)的Java應(yīng)用程序的運(yùn)行偶洋。dex格式是專(zhuān)門(mén)為Dalvik設(shè)計(jì)的一種壓縮格式眶掌,適合內(nèi)存和處理器速度有限的系統(tǒng)荒吏。Google對(duì)其進(jìn)行了特定的優(yōu)化驱还,使得Dalvik具有高效涛碑、簡(jiǎn)潔精堕、節(jié)省資源的特點(diǎn)。從Android系統(tǒng)架構(gòu)圖知蒲障,Dalvik虛擬機(jī)運(yùn)行在Android的運(yùn)行時(shí)庫(kù)層歹篓。

2 Dalvik虛擬機(jī)的功能

Dalvik作為面向Linux瘫证、為嵌入式操作系統(tǒng)設(shè)計(jì)的虛擬機(jī),主要負(fù)責(zé)完成對(duì)象生命周期管理庄撮、堆棧管理背捌、線(xiàn)程管理、安全和異常管理洞斯,以及垃圾回收等毡庆。Dalvik充分利用Linux進(jìn)程管理的特定,對(duì)其進(jìn)行了面向?qū)ο蟮脑O(shè)計(jì)烙如,使得可以同時(shí)運(yùn)行多個(gè)進(jìn)程么抗,而傳統(tǒng)的Java程序通常只能運(yùn)行一個(gè)進(jìn)程,這也是為什么Android不采用JVM的原因亚铁。Dalvik為了達(dá)到優(yōu)化的目的乖坠,底層的操作大多和系統(tǒng)內(nèi)核相關(guān),或者直接調(diào)用內(nèi)核接口刀闷。另外熊泵,Dalvik早期并沒(méi)有JIT編譯器,直到Android2.2才加入了對(duì)JIT的技術(shù)支持甸昏。

3 Dalvik虛擬機(jī)和Java虛擬機(jī)的區(qū)別

本質(zhì)上顽分,Dalvik也是一個(gè)Java虛擬機(jī)。但它特別之處在于沒(méi)有使用JVM規(guī)范施蜜。大多數(shù)Java虛擬機(jī)都是基于棧的結(jié)構(gòu)(詳情請(qǐng)參考:理解Java虛擬機(jī)體系結(jié)構(gòu))卒蘸,而Dalvik虛擬機(jī)則是基于寄存器》基于棧的指令很緊湊缸沃,例如,Java虛擬機(jī)使用的指令只占一個(gè)字節(jié)修械,因而稱(chēng)為字節(jié)碼趾牧。基于寄存器的指令由于需要指定源地址和目標(biāo)地址肯污,因此需要占用更多的指令空間翘单。Dalvik虛擬機(jī)的某些指令需要占用兩個(gè)字節(jié)”脑基于棧和基于寄存器的指令集各有優(yōu)劣哄芜,一般而言,執(zhí)行同樣的功能柬唯,前者需要更多的指令(主要是load和store指令)认臊,而后者需要更多的指令空間。需要更多指令意味著要多占用CPU時(shí)間锄奢,而需要更多指令空間意味著數(shù)據(jù)緩沖(d-cache)更易失效失晴。更多討論冤议,虛擬機(jī)隨談(一):解釋器,樹(shù)遍歷解釋器师坎,基于棧與基于寄存器恕酸,大雜燴 給出了非常詳細(xì)的參考。

Java虛擬機(jī)運(yùn)行的是Java字節(jié)碼胯陋,而Dalvik虛擬機(jī)運(yùn)行的是專(zhuān)有文件格式dex蕊温。在Java程序中,Java類(lèi)會(huì)被編譯成一個(gè)或多個(gè)class文件遏乔,然后打包到j(luò)ar文件中义矛,接著Java虛擬機(jī)會(huì)從相應(yīng)的class文件和jar文件中獲取對(duì)應(yīng)的字節(jié)碼。Android應(yīng)用雖然也使用Java語(yǔ)言盟萨,但是在編譯成class文件后凉翻,還會(huì)通過(guò)DEX工具將所有的class文件轉(zhuǎn)換成一個(gè)dex文件,Dalvik虛擬機(jī)再?gòu)闹凶x取指令和數(shù)據(jù)捻激。dex文件除了減少整體的文件尺寸和I/O操作次數(shù)制轰,也提高了類(lèi)的查找速度。

image

由下圖可以看到胞谭,jar和apk文件的組成結(jié)構(gòu)垃杖,以及class文件和dex文件的差異。dex格式文件使用共享的丈屹、特定類(lèi)型的常量池機(jī)制來(lái)節(jié)省內(nèi)存调俘。常量池存儲(chǔ)類(lèi)中的所有字面常量,它包括字符串常量旺垒、字段常量等值彩库。

image

總的來(lái)說(shuō),Dalvik虛擬機(jī)具有以下特點(diǎn):

  • 使用dex格式的字節(jié)碼先蒋,不兼容Java字節(jié)碼格式
  • 代碼密度小骇钦,運(yùn)行效率高,節(jié)省資源
  • 常量池只使用32位的索引
  • 有內(nèi)存限制
  • 默認(rèn)棧大小是12KB(3個(gè)頁(yè)鞭达,每頁(yè)4KB)
  • 堆默認(rèn)啟動(dòng)大小為2MB司忱,默認(rèn)最大值為16MB
  • 堆支持的最小啟動(dòng)大小為1MB皇忿,支持的最大值為1024MB
  • 堆和棧參數(shù)可以通過(guò)-Xms和-Xmx修改

4 Dalvik系統(tǒng)結(jié)構(gòu)

實(shí)際上畴蹭,Dalvik是基于Apache Harmony(Apache軟件基金會(huì)的Java SE項(xiàng)目)的部分實(shí)現(xiàn),提供了自己的一套庫(kù)鳍烁,即上層Java應(yīng)用程序編寫(xiě)所使用的API叨襟。

image

以上圖示來(lái)自tech-insider。Apache Harmony大體上分為三個(gè)層:操作系統(tǒng)幔荒、Java虛擬機(jī)糊闽、Java類(lèi)庫(kù)梳玫。它的特點(diǎn)在于虛擬機(jī)和類(lèi)庫(kù)內(nèi)部被高度模塊化,每一個(gè)模塊都有一定的接口定義右犹。操作系統(tǒng)層與虛擬機(jī)層之間的接口由Portability Layer定義提澎,它封裝了不同操作系統(tǒng)的差異,為虛擬機(jī)和類(lèi)庫(kù)的本地代碼提供了一套統(tǒng)一的API訪(fǎng)問(wèn)底層系統(tǒng)調(diào)用念链。虛擬機(jī)與類(lèi)庫(kù)之間的接口除了Java規(guī)范定義的JNI盼忌、JVMITI外,還加入了一層虛擬機(jī)接口掂墓,由內(nèi)核類(lèi)和本地代碼組成谦纱。實(shí)現(xiàn)了虛擬機(jī)接口的虛擬機(jī)都可以使用Harmony的類(lèi)庫(kù)實(shí)現(xiàn),并且可以被Harmony提供的同一個(gè)Java啟動(dòng)程序啟動(dòng)君编。

下面是Dalvik虛擬機(jī)的結(jié)構(gòu)圖:

image

一個(gè)應(yīng)用首先經(jīng)過(guò)DX工具將class文件轉(zhuǎn)換成Dalvik虛擬機(jī)可以執(zhí)行的dex文件跨嘉,然后由類(lèi)加載器加載原生類(lèi)和Java類(lèi),接著由解釋器根據(jù)指令集對(duì)Dalvik字節(jié)碼進(jìn)行解釋吃嘿、執(zhí)行祠乃。最后,根據(jù)dvm_arch參數(shù)選擇編譯的目標(biāo)機(jī)體系結(jié)構(gòu)兑燥。

4.1 dex文件結(jié)構(gòu)

dex文件結(jié)構(gòu)和class文件結(jié)構(gòu)差異的地方很多跳纳,但從攜帶的信息上看,dex和class文件是一致的贪嫂。

image
  • header:存儲(chǔ)了各個(gè)數(shù)據(jù)類(lèi)型的起始地址寺庄、偏移量等信息。
  • proto_ids:描述函數(shù)原型信息力崇,包括返回值斗塘,參數(shù)信息。比如“test:()V”
  • methods_ids:函數(shù)信息亮靴,包括所屬類(lèi)及對(duì)應(yīng)的proto信息馍盟。

更多dex格式的內(nèi)容,Android安全–Dex文件格式詳解 這篇文章進(jìn)行了非常詳細(xì)的介紹茧吊。雖然dex文件的結(jié)構(gòu)很緊湊贞岭,但想要運(yùn)行時(shí)的性能得到進(jìn)一步提升,還需要對(duì)dex文件進(jìn)行進(jìn)一步優(yōu)化搓侄。優(yōu)化主要針對(duì)以下幾個(gè)方面:

  • 調(diào)整所有字段的字節(jié)序和對(duì)齊結(jié)構(gòu)中的每一個(gè)域
  • 驗(yàn)證dex文件中的所有類(lèi)
  • 對(duì)一些特定的類(lèi)進(jìn)行優(yōu)化瞄桨,對(duì)方法里的操作碼進(jìn)行優(yōu)化

dex文件經(jīng)過(guò)優(yōu)化后文件大小會(huì)膨脹,大約增加到原來(lái)的1~4倍讶踪。對(duì)于內(nèi)置應(yīng)用芯侥,一般在系統(tǒng)編譯后,便會(huì)生成優(yōu)化文件(odex: Optimized dex)。一個(gè)Android應(yīng)用程序柱查,需要經(jīng)過(guò)以下過(guò)程才可以在Dalvik虛擬機(jī)上運(yùn)行:

  • 把Java源文件編譯成class文件
  • 使用DX工具把class文件轉(zhuǎn)換成dex文件
  • 使用aapt工具把dex文件廓俭、資源文件以及AndroidManifest.xml文件(二進(jìn)制格式)組合成APK
  • 將APK安裝到Android設(shè)備運(yùn)行
image

上圖(來(lái)自網(wǎng)絡(luò))詳盡地展示了最終簽名后的APK是怎么來(lái)的。

4.2 Dalvik類(lèi)加載器

一個(gè)dex文件需要類(lèi)加載器加載原生類(lèi)和Java類(lèi)唉工,然后通過(guò)解釋器根據(jù)指令集對(duì)Dalvik字節(jié)碼進(jìn)行解釋和執(zhí)行研乒。Dalvik類(lèi)加載器使用mmap函數(shù),將dex文件映射到內(nèi)存中淋硝,通過(guò)普通的內(nèi)存讀取操作即可訪(fǎng)問(wèn)dex文件告嘲,然后解析dex文件內(nèi)容并加載其中的類(lèi)到哈希表中。

4.2.1 解析dex

總的來(lái)說(shuō)奖地,dex文件可以抽象為三個(gè)部分:頭部橄唬、索引、數(shù)據(jù)参歹。通過(guò)頭部可以知道索引的位置和數(shù)目仰楚,以及數(shù)據(jù)區(qū)的起始位置。將dex文件映射到內(nèi)存后犬庇,Dalvik會(huì)調(diào)用dexFileParse函數(shù)對(duì)其進(jìn)行分析僧界,分析的結(jié)果放到DexFile數(shù)據(jù)結(jié)構(gòu)中。DexFile中的baseAddr指向映射區(qū)的起始位置臭挽,pClassDefs指向class索引的起始位置捂襟。為了加快class的查找速度,還創(chuàng)建一個(gè)哈希表欢峰,對(duì)class名字進(jìn)行哈希并生成索引葬荷。

4.2.2 加載class

解析工作完成后就進(jìn)行class的加載,加載的類(lèi)需要用ClassObject數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ)纽帖。

typedef struct Object {
    ClassObject* clazz;  // 類(lèi)型對(duì)象
    Lock lock;           // 鎖對(duì)象
} Object;

其中clazz指向ClassObject對(duì)象宠漩,還包含一個(gè)Lock對(duì)象。如果其它線(xiàn)程想要獲取它的鎖懊直,只有等這個(gè)線(xiàn)程釋放扒吁。Dalvik每加載一個(gè)class都會(huì)對(duì)應(yīng)一個(gè)ClassObject對(duì)象,加載過(guò)程會(huì)在內(nèi)存中分配幾個(gè)區(qū)域室囊,分別存放directMethod, virtualMethod, sfield, ifield雕崩。這些信息從dex文件的數(shù)據(jù)區(qū)中讀取。字段Field的定義如下:

struct Field {
    ClassObject* clazz;    //所屬類(lèi)型
    const char* name;      // 變量名稱(chēng)
    const char* signature; // 如“Landroid/os/Debug;”
    u4 accessFlags;        // 訪(fǎng)問(wèn)標(biāo)記
    #ifdef PROFILE_FIELD_ACCESS
        u4 gets;
        u4 puts; 
    #endif 
};

待得到class索引后融撞,實(shí)際的加載由loadClassFromDex來(lái)完成盼铁。首先它會(huì)讀取class的具體數(shù)據(jù),分別加載directMethod, virtualMethod, ifield和sfield懦铺,然后為ClassObject數(shù)據(jù)結(jié)構(gòu)分配內(nèi)存捉貌,并讀取dex文件的相關(guān)信息。加載完成后冬念,將加載的class通過(guò)dvmAddClassToHash函數(shù)放入哈希表趁窃,以方便下次查找;最后急前,通過(guò)dvmLinkClass查找該類(lèi)的超類(lèi)醒陆,如果有接口類(lèi)則加載相應(yīng)的接口類(lèi)。

4.3 Dalvik解釋器

對(duì)于任何虛擬機(jī)來(lái)說(shuō)裆针,解釋器無(wú)疑是核心的部分刨摩,所有的Java字節(jié)碼都經(jīng)過(guò)解釋器解釋執(zhí)行。由于Dalvik解釋器的效率很重要世吨,Android分別實(shí)現(xiàn)了C語(yǔ)言版和各種匯編語(yǔ)言版的解釋器澡刹。解釋器通常是循環(huán)執(zhí)行,需要一個(gè)入口函數(shù)調(diào)用處理程序執(zhí)行第一條指令耘婚,而后每條指令執(zhí)行時(shí)引出下一條指令罢浇,通過(guò)函數(shù)指針調(diào)用處理程序。

4.4 內(nèi)存管理

垃圾收集是Dalvik虛擬機(jī)內(nèi)存管理的核心沐祷。此處只介紹Dalvik虛擬機(jī)的垃圾收集功能嚷闭。垃圾收集的性能在很大程度上影響了一個(gè)Java程序內(nèi)存使用的效率。Dalvik虛擬機(jī)使用常用的Mark-Sweep算法赖临,該算法分Mark階段(標(biāo)記出活動(dòng)對(duì)象)胞锰、Sweep階段(回收垃圾內(nèi)存)和可選的Compact階段(減少堆中的碎片)。Android內(nèi)存管理原理 這篇文章講解得很詳細(xì)兢榨。

垃圾收集的第一步是標(biāo)記出活動(dòng)對(duì)象嗅榕,因?yàn)闆](méi)有辦法識(shí)別那些不可訪(fǎng)問(wèn)的對(duì)象,這樣所有未被標(biāo)記的對(duì)象就是可以回收的垃圾吵聪。當(dāng)進(jìn)行垃圾收集時(shí)誊册,需要停止Dalvik虛擬機(jī)的運(yùn)行(除垃圾收集外),因此垃圾收集又被稱(chēng)作STW(stop-the-world)暖璧。Dalvik虛擬機(jī)在運(yùn)行過(guò)程中要維護(hù)一些狀態(tài)信息案怯,這些信息包括:每個(gè)線(xiàn)程所保存的寄存器、Java類(lèi)中的靜態(tài)字段澎办、局部和全局的JNI引用嘲碱,JVM中的所有函數(shù)調(diào)用會(huì)對(duì)應(yīng)一個(gè)相應(yīng)C的棧幀。每一個(gè)棧幀里可能包含對(duì)對(duì)象的引用局蚀,比如包含對(duì)象引用的局部變量和參數(shù)麦锯。所有這些引用信息被加入到一個(gè)根集合中,然后從根集合開(kāi)始琅绅,遞歸查找可以從根集合出發(fā)訪(fǎng)問(wèn)的對(duì)象扶欣。因此,Mark過(guò)程又叫做追蹤,追蹤所有可被訪(fǎng)問(wèn)的對(duì)象料祠。

垃圾收集的第二步就是回收內(nèi)存骆捧。在Mark階段通過(guò)markBits位圖可以得到所有可訪(fǎng)問(wèn)的對(duì)象集合,而liveBits位圖表示所有已經(jīng)分配的對(duì)象集合髓绽。通過(guò)比較liveBits位圖和markBits位圖的差異就是所有可回收的對(duì)象集合敛苇。Sweep階段調(diào)用free來(lái)釋放這些內(nèi)存給堆。

在底層內(nèi)存實(shí)現(xiàn)上顺呕,Android系統(tǒng)使用的是msspace枫攀,這是一個(gè)輕量級(jí)的malloc實(shí)現(xiàn)。除了創(chuàng)建和初始化用于存儲(chǔ)普通Java對(duì)象的內(nèi)存堆株茶,Android還創(chuàng)建三個(gè)額外的內(nèi)存堆:

  • "livebits"(用來(lái)存放堆上內(nèi)存被占用情況的位圖索引)
  • "markbits"(在GC時(shí)用于標(biāo)注存活對(duì)象的位圖索引)
  • “markstack”(在GC中遍歷存活對(duì)象引用的標(biāo)注棧)

虛擬機(jī)通過(guò)一個(gè)名為gHs的全局HeapSource變量來(lái)操控GC內(nèi)存堆来涨,而HeapSource里通過(guò)heaps數(shù)組可以管理多個(gè)堆(Heap),以滿(mǎn)足動(dòng)態(tài)調(diào)整GC內(nèi)存堆大小的要求启盛。另外HeapSource里還維護(hù)一個(gè)名為"livebits"的位圖索引蹦掐,以跟蹤各個(gè)堆(Heap)的內(nèi)存使用情況。剩下兩個(gè)數(shù)據(jù)結(jié)構(gòu)"markstack"和"markbits"都是用在垃圾回收階段驰徊。

image

上圖中"livebits"維護(hù)堆上已用的內(nèi)存信息笤闯,而"markbits"這個(gè)位圖索引則指向存活的對(duì)象。 A棍厂、C颗味、F、G牺弹、H對(duì)象需要保留浦马,因此"markbits"分別指向他們(最后的H對(duì)象尚在標(biāo)注過(guò)程中,因此沒(méi)有指針指向它)张漂。而"markstack"就是在標(biāo)注過(guò)程中跟蹤當(dāng)前需要處理的對(duì)象要用到的標(biāo)志棧晶默,此時(shí)其保存了正在處理的對(duì)象F、G和H航攒。

4.5 Dalvik的啟動(dòng)流程

Dalvik進(jìn)程管理是依賴(lài)于linux的進(jìn)程體系結(jié)構(gòu)的磺陡,如要為應(yīng)用程序創(chuàng)建一個(gè)進(jìn)程,它會(huì)使用linux的fork機(jī)制來(lái)復(fù)制一個(gè)進(jìn)程漠畜。Zygote是一個(gè)虛擬機(jī)進(jìn)程币他,同時(shí)也是一個(gè)虛擬機(jī)實(shí)例的孵化器,它通過(guò)init進(jìn)程啟動(dòng)憔狞。之前的文章有對(duì)此過(guò)程有詳細(xì)介紹:Android系統(tǒng)啟動(dòng)分析(Init->Zygote->SystemServer->Home activity)蝴悉。此處分析Dalvik虛擬機(jī)啟動(dòng)的相關(guān)過(guò)程。

image

AndroidRuntime類(lèi)主要做了以下幾件事情:

  • 調(diào)用startVM創(chuàng)建一個(gè)Dalvik虛擬機(jī)瘾敢,JNI_CreateJavaVM真正創(chuàng)建并初始化虛擬機(jī)實(shí)例
  • 調(diào)用startReg注冊(cè)Android核心類(lèi)的JNI方法
  • 通過(guò)Zygote進(jìn)程進(jìn)入Java層

在JNI中拍冠,dvmCreateJNIEnv為當(dāng)前線(xiàn)程創(chuàng)建和初始化一個(gè)JNI環(huán)境尿这,即一個(gè)JNIEnvExt對(duì)象。最后調(diào)用dvmStartup來(lái)初始化前面創(chuàng)建的Dalvik虛擬機(jī)實(shí)例庆杜。函數(shù)dvmInitZygote調(diào)用了系統(tǒng)的setpgid來(lái)設(shè)置當(dāng)前進(jìn)程射众,即Zygote進(jìn)程的進(jìn)程組ID。這一步完成后欣福,Dalvik虛擬機(jī)的創(chuàng)建和初始化工作就完成了责球。

5 Android的啟動(dòng)

  • 啟動(dòng)電源焦履,加載引導(dǎo)程序到RAM
  • BootLoader引導(dǎo)
  • Linux Kernel啟動(dòng)
  • Init進(jìn)程創(chuàng)建
  • Init fork出Zygote進(jìn)程拓劝,Zygote進(jìn)程創(chuàng)建虛擬機(jī);創(chuàng)建系統(tǒng)服務(wù)
  • Android Home Launcher啟動(dòng)
image

參考:

《Android技術(shù)內(nèi)幕》
Dalvik虛擬機(jī)簡(jiǎn)要介紹和學(xué)習(xí)計(jì)劃
深入理解Android(二):Java虛擬機(jī)Dalvik
dalvik虛擬內(nèi)存管理之二——垃圾收集
Dalvik虛擬機(jī)的啟動(dòng)過(guò)程分析

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末嘉裤,一起剝皮案震驚了整個(gè)濱河市郑临,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌屑宠,老刑警劉巖厢洞,帶你破解...
    沈念sama閱讀 217,509評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異典奉,居然都是意外死亡躺翻,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)卫玖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)公你,“玉大人,你說(shuō)我怎么就攤上這事假瞬∩驴浚” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,875評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵脱茉,是天一觀的道長(zhǎng)剪芥。 經(jīng)常有香客問(wèn)我,道長(zhǎng)琴许,這世上最難降的妖魔是什么税肪? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,441評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮榜田,結(jié)果婚禮上益兄,老公的妹妹穿的比我還像新娘。我一直安慰自己串慰,他們只是感情好偏塞,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,488評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著邦鲫,像睡著了一般灸叼。 火紅的嫁衣襯著肌膚如雪神汹。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,365評(píng)論 1 302
  • 那天古今,我揣著相機(jī)與錄音屁魏,去河邊找鬼。 笑死捉腥,一個(gè)胖子當(dāng)著我的面吹牛氓拼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播抵碟,決...
    沈念sama閱讀 40,190評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼桃漾,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了拟逮?” 一聲冷哼從身側(cè)響起撬统,我...
    開(kāi)封第一講書(shū)人閱讀 39,062評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎敦迄,沒(méi)想到半個(gè)月后恋追,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,500評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡罚屋,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,706評(píng)論 3 335
  • 正文 我和宋清朗相戀三年苦囱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片脾猛。...
    茶點(diǎn)故事閱讀 39,834評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡撕彤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出尖滚,到底是詐尸還是另有隱情喉刘,我是刑警寧澤,帶...
    沈念sama閱讀 35,559評(píng)論 5 345
  • 正文 年R本政府宣布漆弄,位于F島的核電站睦裳,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏撼唾。R本人自食惡果不足惜廉邑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,167評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望倒谷。 院中可真熱鬧蛛蒙,春花似錦、人聲如沸渤愁。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,779評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)抖格。三九已至诺苹,卻和暖如春咕晋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背收奔。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,912評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工掌呜, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人坪哄。 一個(gè)月前我還...
    沈念sama閱讀 47,958評(píng)論 2 370
  • 正文 我出身青樓质蕉,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親翩肌。 傳聞我的和親對(duì)象是個(gè)殘疾皇子模暗,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,779評(píng)論 2 354

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