Android內(nèi)存優(yōu)化實(shí)戰(zhàn)篇

聲明:原創(chuàng)作品,轉(zhuǎn)載請(qǐng)注明出處http://www.lxweimin.com/p/87beb3b34771

作為一名Android開(kāi)發(fā)者,對(duì)APP內(nèi)存優(yōu)化必須要有一定的了解,今天就總結(jié)下Android內(nèi)存優(yōu)化那些事。

什么是內(nèi)存

首先看下這里的內(nèi)存到底指的是什么?可以看下面這張圖:


Android存儲(chǔ)

手機(jī)中主要的存儲(chǔ)部分分兩塊RAM和ROM,RAM存儲(chǔ)程序的運(yùn)行時(shí)數(shù)據(jù),設(shè)備關(guān)機(jī)就會(huì)清空,我們也稱之為內(nèi)存;ROM也就是磁盤(pán),存放一些永久的數(shù)據(jù)。

上圖我們看到這個(gè)RAM中還有一個(gè)zRAM分區(qū),這個(gè)zRAM分區(qū)會(huì)在內(nèi)存不足時(shí)發(fā)揮作用,稍后會(huì)說(shuō)到。

到這里簡(jiǎn)單介紹了手機(jī)的內(nèi)存是指什么,當(dāng)我們不斷打開(kāi)APP時(shí),手機(jī)的內(nèi)存會(huì)被占的越來(lái)越多,而我們知道我們的手機(jī)總內(nèi)存是一定的,那么當(dāng)內(nèi)存不夠時(shí)手機(jī)會(huì)發(fā)生什么呢?

內(nèi)存不夠怎么辦

當(dāng)我們手機(jī)內(nèi)存不足時(shí),系統(tǒng)會(huì)有兩套機(jī)制發(fā)揮作用。分別是內(nèi)核交換守護(hù)進(jìn)程低內(nèi)存終止守護(hù)進(jìn)程

內(nèi)核交換守護(hù)進(jìn)程(kswapd)

內(nèi)核交換守護(hù)進(jìn)程 (kswapd) 是 Linux 內(nèi)核的一部分,用于將已使用內(nèi)存轉(zhuǎn)換為可用內(nèi)存。當(dāng)設(shè)備上的可用內(nèi)存不足時(shí),該守護(hù)進(jìn)程將變?yōu)榛顒?dòng)狀態(tài)。Linux 內(nèi)核設(shè)有可用內(nèi)存上下限閾值。當(dāng)可用內(nèi)存降至下限閾值以下時(shí),kswapd 開(kāi)始回收內(nèi)存。當(dāng)可用內(nèi)存達(dá)到上限閾值時(shí),kswapd 停止回收內(nèi)存。
kswapd可以刪除不再被使用到的內(nèi)存,如下圖:



kswapd也可以對(duì)暫時(shí)不用的內(nèi)存移到zRAM進(jìn)行壓縮,如果被用到時(shí),會(huì)解壓重新移到到RAM中,如下圖:


低內(nèi)存終止守護(hù)進(jìn)程

很多時(shí)候,kswapd 不能為系統(tǒng)釋放足夠的內(nèi)存。在這種情況下,系統(tǒng)會(huì)使用 onTrimMemory() 通知應(yīng)用內(nèi)存不足,應(yīng)該減少其分配量。如果這還不夠,內(nèi)核會(huì)開(kāi)始終止進(jìn)程以釋放內(nèi)存。它會(huì)使用低內(nèi)存終止守護(hù)進(jìn)程 (LMK) 來(lái)執(zhí)行此操作。

LMK 使用一個(gè)名為 oom_adj_score 的“內(nèi)存不足”分值來(lái)確定正在運(yùn)行的進(jìn)程的優(yōu)先級(jí),以此決定要終止的進(jìn)程。最高得分的進(jìn)程最先被終止。后臺(tái)應(yīng)用最先被終止,系統(tǒng)進(jìn)程最后被終止。下表列出了從高到低的 LMK 評(píng)分類別。評(píng)分最高的類別,即第一行中的項(xiàng)目將最先被終止:

[站外圖片上傳中...(image-c78455-1621768365460)]

以下是上表中各種類別的說(shuō)明:

  • 后臺(tái)應(yīng)用:之前運(yùn)行過(guò)且當(dāng)前不處于活動(dòng)狀態(tài)的應(yīng)用。LMK 將首先從具有最高 oom_adj_score 的應(yīng)用開(kāi)始終止后臺(tái)應(yīng)用。

  • 上一個(gè)應(yīng)用:最近用過(guò)的后臺(tái)應(yīng)用。上一個(gè)應(yīng)用比后臺(tái)應(yīng)用具有更高的優(yōu)先級(jí)(得分更低),因?yàn)橄啾饶硞€(gè)后臺(tái)應(yīng)用,用戶更有可能切換到上一個(gè)應(yīng)用。

  • 主屏幕應(yīng)用:這是啟動(dòng)器應(yīng)用。終止該應(yīng)用會(huì)使壁紙消失。

  • 服務(wù):服務(wù)由應(yīng)用啟動(dòng),可能包括同步或上傳到云端。

  • 可覺(jué)察的應(yīng)用:用戶可通過(guò)某種方式察覺(jué)到的非前臺(tái)應(yīng)用,例如運(yùn)行一個(gè)顯示小界面的搜索進(jìn)程或聽(tīng)音樂(lè)。

  • 前臺(tái)應(yīng)用:當(dāng)前正在使用的應(yīng)用。終止前臺(tái)應(yīng)用看起來(lái)就像是應(yīng)用崩潰了,可能會(huì)向用戶提示設(shè)備出了問(wèn)題。

  • 持久性(服務(wù)):這些是設(shè)備的核心服務(wù),例如電話和 WLAN。

  • 系統(tǒng):系統(tǒng)進(jìn)程。這些進(jìn)程被終止后,手機(jī)可能看起來(lái)即將重新啟動(dòng)。

  • 原生:系統(tǒng)使用的極低級(jí)別的進(jìn)程(例如,kswapd)。

設(shè)備制造商可以更改 LMK 的行為。

設(shè)備對(duì)內(nèi)存的影響

接下來(lái)可以看下不同設(shè)備,內(nèi)存使用情況:

2G內(nèi)存

2G

簡(jiǎn)單分析下,上圖展示了2G內(nèi)存設(shè)備的內(nèi)存使用情況,當(dāng)可用內(nèi)存下降到某一閾值,即圖中的kswapd threshold,這時(shí)kswapd會(huì)發(fā)揮作用,將緩存的內(nèi)存轉(zhuǎn)為使用內(nèi)存。如果使用的內(nèi)存越來(lái)越多,達(dá)到lmk threshold,那么低內(nèi)存終止守護(hù)進(jìn)程就會(huì)發(fā)揮作用,根據(jù)上面的優(yōu)先級(jí)來(lái)殺死后臺(tái)進(jìn)程獲取更多內(nèi)存。

512M內(nèi)存

512M

上圖顯示了只有512M內(nèi)存的設(shè)備內(nèi)存使用情況,可以看到由于總內(nèi)存很小,隨著使用時(shí)長(zhǎng)的增加,內(nèi)存很快就到了低內(nèi)存終止守護(hù)進(jìn)程閾值線,基本打開(kāi)一個(gè)應(yīng)用就會(huì)殺死后臺(tái)一個(gè)應(yīng)用,使用體驗(yàn)很差。
接下來(lái)看下下面這張圖:


上圖顯示了應(yīng)用數(shù)據(jù)量和內(nèi)存占用關(guān)系PSS(下面會(huì)講到),一般數(shù)據(jù)量越多內(nèi)存占用越多,紅黃綠分別代表不同的手機(jī)設(shè)備,手機(jī)配置依次升高。

RSS、PSS和USS

接下來(lái)看幾個(gè)內(nèi)存概念:RSS、PSS和USS。在講這幾個(gè)概念前首先來(lái)了解下內(nèi)存的占用量是如何計(jì)算的,內(nèi)存是分頁(yè)計(jì)算的,一個(gè)應(yīng)用內(nèi)存可能會(huì)占用好幾頁(yè),如下圖所示:



當(dāng)然,也會(huì)存在幾個(gè)應(yīng)用共享內(nèi)存頁(yè)面,例如,Google Play 服務(wù)和某個(gè)游戲應(yīng)用可能會(huì)共享位置信息服務(wù),如下所示:


為了確定應(yīng)用的內(nèi)存占用量,可以使用以下任一指標(biāo):

  • 常駐內(nèi)存大小 (RSS):應(yīng)用使用的共享和非共享頁(yè)面的數(shù)量
  • 按比例分?jǐn)偟膬?nèi)存大小 (PSS):應(yīng)用使用的非共享頁(yè)面的數(shù)量加上共享頁(yè)面的均勻分?jǐn)倲?shù)量(例如,如果三個(gè)進(jìn)程共享 3MB,則每個(gè)進(jìn)程的 PSS 為 1MB)
  • 獨(dú)占內(nèi)存大小 (USS):應(yīng)用使用的非共享頁(yè)面數(shù)量(不包括共享頁(yè)面)

如果操作系統(tǒng)想要知道所有進(jìn)程使用了多少內(nèi)存,那么 PSS 非常有用,因?yàn)轫?yè)面只會(huì)統(tǒng)計(jì)一次。計(jì)算 PSS 需要花很長(zhǎng)時(shí)間,因?yàn)橄到y(tǒng)需要確定共享的頁(yè)面以及共享頁(yè)面的進(jìn)程數(shù)量。RSS 不區(qū)分共享和非共享頁(yè)面(因此計(jì)算起來(lái)更快),更適合跟蹤內(nèi)存分配量的變化。
我們可以通過(guò)adb來(lái)直觀的看下某個(gè)APP的內(nèi)存占用情況,adb命令如下:

adb shell dumpsys meminfo 應(yīng)用完整包名

顯示結(jié)果如下:

                   Pss  Private  Private  SwapPss     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------
  Native Heap     6736     6680        4      114    22528    17971     4556
  Dalvik Heap        0        0        0        0     5502     2751     2751
        Stack       80       80        0        0                           
       Ashmem       21        0       20        0                           
      Gfx dev      280      280        0        0                           
    Other dev        2        0        0        0                           
     .so mmap     8081      196     5848       11                           
    .apk mmap      319        0       72        0                           
    .ttf mmap       55        0       28        0                           
    .dex mmap     6261       16     5180        0                           
    .oat mmap       75        0       20        0                           
    .art mmap     7913     7180      248       69                           
   Other mmap       68        4        0        0                           
   EGL mtrack    18496    18496        0        0                           
    GL mtrack     3348     3348        0        0                           
      Unknown     7139     7064       28       40                           
        TOTAL    59108    43344    11448      234    28030    20722     7307
 
 App Summary
                       Pss(KB)
                        ------
           Java Heap:     7428
         Native Heap:     6680
                Code:    11360
               Stack:       80
            Graphics:    22124
       Private Other:     7120
              System:     4316
 
               TOTAL:    59108       TOTAL SWAP PSS:      234
 
 Objects
               Views:       16         ViewRootImpl:        1
         AppContexts:        5           Activities:        1
              Assets:        7        AssetManagers:        0
       Local Binders:       16        Proxy Binders:       31
       Parcel memory:        4         Parcel count:       17
    Death Recipients:        2      OpenSSL Sockets:        0
            WebViews:        0
 
 SQL
         MEMORY_USED:        0
  PAGECACHE_OVERFLOW:        0          MALLOC_SIZE:        0

我們重點(diǎn)看下``App Summary`部分,這部分展示了APP內(nèi)存(PSS)總占有量,以及各個(gè)內(nèi)存占用明細(xì):

  • Java:從 Java 或 Kotlin 代碼分配的對(duì)象的內(nèi)存。

  • Native:從 C 或 C++ 代碼分配的對(duì)象的內(nèi)存。即使您的應(yīng)用中不使用 C++,您也可能會(huì)看到此處使用了一些原生內(nèi)存,因?yàn)榧词鼓帉?xiě)的代碼采用 Java 或 Kotlin 語(yǔ)言,Android 框架仍使用原生內(nèi)存代表您處理各種任務(wù),如處理圖像資源和其他圖形。

  • Graphics:圖形緩沖區(qū)隊(duì)列為向屏幕顯示像素(包括 GL 表面、GL 紋理等等)所使用的內(nèi)存。(請(qǐng)注意,這是與 CPU 共享的內(nèi)存,不是 GPU 專用內(nèi)存。)

  • Stack:您的應(yīng)用中的原生堆棧和 Java 堆棧使用的內(nèi)存。這通常與您的應(yīng)用運(yùn)行多少線程有關(guān)。

  • Code:您的應(yīng)用用于處理代碼和資源(如 dex 字節(jié)碼、經(jīng)過(guò)優(yōu)化或編譯的 dex 代碼、.so 庫(kù)和字體)的內(nèi)存。

  • Others:您的應(yīng)用使用的系統(tǒng)不確定如何分類的內(nèi)存。

  • System:系統(tǒng)內(nèi)存。

減小應(yīng)用內(nèi)存占用

接下來(lái)看下如何減小我們APP內(nèi)存的占用,這里有兩種方式:

  • 減小Java Heap內(nèi)存
  • 減小應(yīng)用包體積

減小Java Heap內(nèi)存

這里你可能會(huì)比較好奇,上面我們可以看到內(nèi)存有很多部分組成,為什么這里偏偏只減小Java Heap的內(nèi)存就可以。主要是其他內(nèi)存分析比較困難,Android官方也不太推薦分析除了Java Heap之外的內(nèi)存,主要有以下幾個(gè)原因:

  • 工具不能很好支持
  • 用戶接口不友好
  • 需要非常深的系統(tǒng)底層知識(shí)
  • root設(shè)備,或者重新編譯源碼
  • 很多內(nèi)存無(wú)法控制

下面這張是Android系統(tǒng)架構(gòu)圖,從圖中也可以看出,系統(tǒng)底層都是直接或者間接和應(yīng)用層有關(guān),就是說(shuō)底層占用的內(nèi)存和Java Heap內(nèi)存都是有關(guān)聯(lián)的,優(yōu)化了Java Heap內(nèi)存也就間接優(yōu)化了其他內(nèi)存部分。


接下來(lái)具體看下如何減小Java Heap內(nèi)存,首先來(lái)了解下什么是Java Heap,Java Heap即Java堆,也是虛擬機(jī)對(duì)象主要存放的地方,一般也是垃圾回收的重點(diǎn)位置。當(dāng)然Java 虛擬機(jī)除了Java堆外還有其他分區(qū):程序計(jì)數(shù)器、方法區(qū)、虛擬機(jī)棧和本地方法棧,這里由于篇幅有限這幾個(gè)分區(qū)作用就不過(guò)多介紹了,如下:


Java 內(nèi)存分區(qū)

由于Java虛擬機(jī)是分代回收垃圾,在Java 7中Java Heap被分為新生代、老年代和永久代,新生代又分為Eden、From Survivor和To Survivor區(qū),他們的大小比例是8:1:1,來(lái)說(shuō)下它的工作機(jī)制,首先新生成的對(duì)象會(huì)被分配到Eden區(qū),當(dāng)Eden區(qū)內(nèi)存滿了時(shí)會(huì)發(fā)生一次小型的垃圾回收,回收時(shí)會(huì)將Eden區(qū)中存活的對(duì)象復(fù)制到From Survivor區(qū)中,然后把Eden區(qū)清空。當(dāng)From Survivor也滿了,就會(huì)把Eden區(qū)和From Survivor中存活的對(duì)象復(fù)制到To Survivor區(qū)中,然后清空Eden和From Survivor區(qū),接著會(huì)把From Survivor區(qū)和To Survivor區(qū)做交換,保持To Survivor區(qū)中的對(duì)象為空,就這樣不斷重復(fù),當(dāng)To Survivor中的空間也滿了,無(wú)法存在Eden和From Survivor區(qū)中的對(duì)象時(shí),就會(huì)把他們存入老年代。另外當(dāng)某個(gè)對(duì)象在Survivor區(qū)中經(jīng)歷一次GC而存活下來(lái),那么他的年齡就會(huì)加一,默認(rèn)情況下當(dāng)超過(guò)15歲時(shí)就會(huì)被丟入老年代中。當(dāng)老年代空間也滿了虛擬機(jī)會(huì)發(fā)生一次Full GC,一般大對(duì)象會(huì)直接放入老年代,比如大數(shù)組這種需要連續(xù)存儲(chǔ)空間的。永久代一般存放靜態(tài)對(duì)象比如class文件,靜態(tài)方法、常量等。永久代對(duì)垃圾回收沒(méi)有顯著的影響,主要回收無(wú)用類和廢棄常量。在Java 8中移除了永久代改為了元空間(Metaspace),因此不會(huì)再出現(xiàn)“java.lang.OutOfMemoryError: PermGen error”錯(cuò)誤。

對(duì)象存活檢測(cè)

上面我們了解了有關(guān)Java Heap內(nèi)存分配和回收相關(guān)原理,接下來(lái)你可能會(huì)有疑問(wèn),Java虛擬機(jī)是如何判斷一個(gè)對(duì)象是否是存活狀態(tài)。換句話說(shuō)一個(gè)對(duì)象在什么情況下該被回收呢,這個(gè)問(wèn)題自然而然就是對(duì)象不再用到的時(shí)候就可以被回收,而這個(gè)“不再被用到”就是這個(gè)對(duì)象不被任何一個(gè)對(duì)象所引用的意思。這里主要有兩種方式來(lái)判斷一個(gè)對(duì)象有沒(méi)有被其他對(duì)象引用:引用計(jì)數(shù)法根搜索算法

引用計(jì)數(shù)法

引用計(jì)數(shù)法顧名思義,就是在這個(gè)對(duì)象里有一個(gè)計(jì)數(shù)的量,當(dāng)這個(gè)對(duì)象被其他對(duì)象引用時(shí)這個(gè)計(jì)數(shù)量就會(huì)加1,比如被2兩個(gè)對(duì)象引用就是2,并且當(dāng)其他對(duì)象不再引用這個(gè)對(duì)象時(shí),這個(gè)計(jì)數(shù)量會(huì)相應(yīng)減1。當(dāng)這個(gè)計(jì)數(shù)量為0時(shí)就代表這個(gè)對(duì)象不被任何對(duì)象引用,那么虛擬機(jī)在下次垃圾回收時(shí)就會(huì)回收這個(gè)對(duì)象。不過(guò)這種方式有一個(gè)弊端,就是互相引用,也就是有兩個(gè)對(duì)象互相引用對(duì)方,那么他們的計(jì)數(shù)值都是1,然而這兩個(gè)對(duì)象除了互相引用外就沒(méi)有其他對(duì)象引用了,其實(shí)針對(duì)這種情況,這兩個(gè)對(duì)象都應(yīng)該被回收的,但是他們的計(jì)數(shù)值都是1,導(dǎo)致虛擬機(jī)無(wú)法對(duì)他們進(jìn)行回收。


引用計(jì)數(shù)法弊端

為了解決這個(gè)問(wèn)題,虛擬機(jī)使用了另一種方式也就是 根搜索算法

根搜索算法

這種算法的基本思路:

(1)通過(guò)一系列名為“GC Roots”的對(duì)象作為起始點(diǎn),尋找對(duì)應(yīng)的引用節(jié)點(diǎn)。

(2)找到這些引用節(jié)點(diǎn)后,從這些節(jié)點(diǎn)開(kāi)始向下繼續(xù)尋找它們的引用節(jié)點(diǎn)。

(3)重復(fù)(2)。

(4)搜索所走過(guò)的路徑稱為引用鏈,當(dāng)一個(gè)對(duì)象到GC Roots沒(méi)有任何引用鏈相連時(shí),就證明此對(duì)象是不可用的。

在java語(yǔ)言中,可作為GCRoot的對(duì)象包括以下幾種:

  • java虛擬機(jī)棧(棧幀中的本地變量表)中的引用的對(duì)象。

  • 方法區(qū)中的類靜態(tài)屬性引用的對(duì)象。

  • 方法區(qū)中的常量引用的對(duì)象。

  • 本地方法棧中JNI本地方法的引用對(duì)象。


    根搜索算法

內(nèi)存泄漏和內(nèi)存溢出

了解了根搜索算法后,我們知道當(dāng)一個(gè)對(duì)象不在引用鏈上的時(shí)候就可以對(duì)它進(jìn)行回收了,但是可能存在一種情況就是假如我們想回收一個(gè)對(duì)象,但是由于某些原因?qū)е逻@個(gè)對(duì)象一直在引用鏈上,這樣這個(gè)對(duì)象就一直無(wú)法被回收了。我們稱這種現(xiàn)象為內(nèi)存泄漏。當(dāng)我們的應(yīng)用很多地方存在這種內(nèi)存泄漏現(xiàn)象時(shí),隨著應(yīng)用的使用,內(nèi)存占用會(huì)越來(lái)越高,當(dāng)內(nèi)存使用量達(dá)到系統(tǒng)規(guī)定的上限,APP就會(huì)報(bào)一個(gè)OutOfMemery的異常,我們稱這種現(xiàn)象為內(nèi)存溢出。

那么什么情況會(huì)導(dǎo)致內(nèi)存泄漏呢,這里簡(jiǎn)單羅列下:

  • 集合類的不規(guī)范使用
  • static修飾的成員變量
  • 非靜態(tài)內(nèi)部類或者匿名內(nèi)部類
  • 資源對(duì)象使用后未關(guān)閉

上面只是簡(jiǎn)單的列了下可能會(huì)導(dǎo)致內(nèi)存泄漏的情況,更加詳細(xì)的原因可以參看其他相關(guān)內(nèi)存泄漏的文章。

知道內(nèi)存泄漏的現(xiàn)象及其后果后,接下來(lái)我們就應(yīng)該去解決我們應(yīng)用中的內(nèi)存泄漏問(wèn)題,但是導(dǎo)致內(nèi)存泄漏的代碼往往很隱蔽我們一時(shí)是很難排查的,這是就可以借助一些內(nèi)存分析工具。比如可以用Android Studio自帶的性能分析工具Profiler,或者也可以在應(yīng)用工程中集成一個(gè)內(nèi)存分析的三方庫(kù)LeakCanary,這個(gè)庫(kù)具體的使用方式可以上他們的官網(wǎng)了解LeakCanary

減小包體積

上面我們用大量篇幅來(lái)分析了減小Java Heap大小來(lái)優(yōu)化內(nèi)存,其實(shí)應(yīng)用的安裝包大小對(duì)內(nèi)存也是由影響的,比如如果安裝包中有很多圖片等資源的話,這會(huì)增加Java Heap、Native Heap和Graphics的內(nèi)存占用量。當(dāng)然還有其他一些文件也會(huì)有影響,具體表格如下:


包體積對(duì)應(yīng)用內(nèi)存的影響
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,333評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,491評(píng)論 3 416
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 176,263評(píng)論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 62,946評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,708評(píng)論 6 410
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 55,186評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,255評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 42,409評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,939評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,774評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,976評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,518評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,209評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 34,641評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 35,872評(píng)論 1 286
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,650評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,958評(píng)論 2 373