android內(nèi)存泄漏分析與檢測(cè)

對(duì)于一個(gè)android開(kāi)發(fā)來(lái)說(shuō),內(nèi)存優(yōu)化是一個(gè)亙古不變的話題珍手。很多東西看過(guò)了當(dāng)時(shí)理解了准夷,但是過(guò)一段時(shí)間會(huì)忘,今天就系統(tǒng)的記錄一下豪嗽。

先畫(huà)個(gè)思維導(dǎo)圖谴蔑,免得寫(xiě)起來(lái)沒(méi)有章法豌骏。

image.png

想要做內(nèi)存優(yōu)化,首先必須得jvm的內(nèi)存模型有一定的了解隐锭。

JVM內(nèi)存模型

java的內(nèi)存管理是交給GC(Garbage Collection)來(lái)處理的,GC會(huì)幫助我們回收不再使用的內(nèi)存資源窃躲。但是也有些時(shí)候由于程序員的疏忽大意,導(dǎo)致GC無(wú)法回收,此時(shí)便造成了內(nèi)存泄漏.

懶得畫(huà)了,借用網(wǎng)上的圖片大致說(shuō)明下


1592745-3f82fafa66408ed9.png

jvm運(yùn)行時(shí)模型包括

1.方法區(qū)(Method Area)
2.堆(Heap)
3.虛擬機(jī)棧(VM Stack也叫JavaStack)
4.本地方法棧(Native Method Stack)
5.程序計(jì)數(shù)器(Program Counter Register)

1和2也就是方法區(qū)和堆是線程間共享的,而345是線程私有的!

那么為什么堆和方法區(qū)是線程間共享的而其他區(qū)域卻是線程間隔離的呢?

首先我們的理解方法區(qū)和堆都負(fù)責(zé)存放哪些信息

  • 堆 (Heap)
    \color{blue}{線程共享區(qū)域}
    用于存儲(chǔ)對(duì)象實(shí)例,內(nèi)存不連續(xù),生命周期不確定,是GC重點(diǎn)回收區(qū)域,當(dāng)內(nèi)存不足時(shí)會(huì)觸發(fā)OutOfMemory異常
  • 方法區(qū)(Method Area)
    \color{blue}{線程共享區(qū)域}
    主要負(fù)責(zé)存儲(chǔ)被虛擬機(jī)加載的類信息蒂窒、常量、靜態(tài)變量衰抑、即時(shí)編譯器編譯后的代碼等數(shù)據(jù),當(dāng)內(nèi)存不足時(shí)同樣會(huì)觸發(fā)OutOfMemory一樣\color{green}{其實(shí)方法區(qū)只是邏輯上的獨(dú)立,實(shí)際上方法區(qū)還是屬于堆的一部分,因此方法區(qū)也是GC負(fù)責(zé)回收的區(qū)域}!
    \color{red}{方法區(qū)的垃圾回收主要有兩種啦撮,分別是對(duì)廢棄常量的回收(常量池的回收)和對(duì)無(wú)用類的回收(類的卸載)}
    20170329213804490.png

\color{red}{當(dāng)一個(gè)常量對(duì)象不再任何地方被引用的時(shí)候,則被標(biāo)記為廢棄常量,這個(gè)常量可以被回收抠璃。}

  • 虛擬機(jī)棧(JavaStack)
    \color{#662492}{線程間私有}
    存儲(chǔ)局部變量表、操作棧采盒、動(dòng)態(tài)鏈接磅氨、方法出口等信息,Java每個(gè)方法被執(zhí)行時(shí)都會(huì)創(chuàng)建一個(gè)棧幀烦租,并壓入JavaStack中
    畫(huà)張圖幫助理解
JavaStack

那么我現(xiàn)在知道Java棧中存放局部變量等信息了
此時(shí)我們來(lái)思考上面的問(wèn)題(為什么java棧要線程隔離呢?)
試想下如果在并發(fā)多線程時(shí),如果A線程可以訪問(wèn)B線程中調(diào)用的方法中的局部變量,那么程序是不是就亂了套了
棧可能觸發(fā)兩種異常
1.在單線程時(shí),如果線程申請(qǐng)的棧深度超出了虛擬機(jī)允許的最大深度時(shí),會(huì)拋出StackOverflow異常!比如遞歸遍歷的時(shí)候不斷壓棧就可能會(huì)爬出StackOverflow異常
2.虛擬機(jī)棧可以動(dòng)態(tài)擴(kuò)展,在多線程時(shí),當(dāng)棿蠡牵空間超出了虛擬機(jī)分配的大小時(shí),此時(shí)當(dāng)線程申請(qǐng)開(kāi)辟棧空間時(shí)會(huì)觸發(fā)OutOfMemory異常

  • 本地方法棧(Native Heap)
    \color{#662492}{線程間私有}
    不做過(guò)多講解,其實(shí)作用和java棧一樣,只不過(guò)存儲(chǔ)的是c/c++等JNI調(diào)用的方法中的信息
  • 程序計(jì)數(shù)器(Program Counter Register)
    \color{#662492}{線程間私有,生命周期與線程一致}
    存儲(chǔ)正在執(zhí)行的虛擬機(jī)字節(jié)碼的指令的地址
    如果當(dāng)前線程正在執(zhí)行的是一個(gè)Java方法,這個(gè)計(jì)數(shù)器記錄的是正在執(zhí)行的虛擬機(jī)字節(jié)碼指令的地址;如果正在執(zhí)行的是一個(gè)Native方法绑嘹,這個(gè)計(jì)數(shù)器值null稽荧。

    那么程序計(jì)數(shù)器為什么是線程間私有呢?
    我們知道java并發(fā)多線程時(shí),其實(shí)時(shí)輪換執(zhí)行,其實(shí)同一時(shí)間只有一個(gè)線程能夠得到執(zhí)行!
    假如A線程執(zhí)行到M方法的第8行此時(shí)切換到B線程執(zhí)行, 此時(shí)程序計(jì)數(shù)器會(huì)記錄下M方法第8行的字節(jié)碼指令地址,等到再次輪換到A線程執(zhí)行的時(shí)候,就接著從第8行往下執(zhí)行工腋。設(shè)計(jì)成線程間私有,每個(gè)線程擁有一個(gè)自己的程序計(jì)數(shù)器,彼此之間不會(huì)干擾!
    \color{red}{程序計(jì)數(shù)器是JVM內(nèi)存模型中唯一不會(huì)觸發(fā)OOM異常的區(qū)域}

什么是內(nèi)存泄漏,什么情況下會(huì)發(fā)生內(nèi)存泄漏?

上面說(shuō)了,java/kotlin new出來(lái)的對(duì)象放在 "堆"中的,那么GC是如何判斷一個(gè)對(duì)象是否應(yīng)該被回收了呢?

判斷java對(duì)象是否該被回收通常有兩種方式

1.引用計(jì)數(shù)
比如A被B引用,計(jì)數(shù)加一,A又被C引用計(jì)數(shù)加一,B對(duì)象釋放了,那么A的引用計(jì)數(shù)就減一。當(dāng)引用計(jì)數(shù)為0時(shí)擅腰,則該對(duì)象可以被回收!但是無(wú)法解決循環(huán)引用的問(wèn)題

2.GCRoot可達(dá)性
從一個(gè)對(duì)象不斷的向上追溯引用,如果無(wú)法追溯到GCRoot的時(shí)候,那么這個(gè)對(duì)象就可以被回收了!
比方說(shuō)A引用B,B又引用A,但是此時(shí)A和B都沒(méi)有被其他對(duì)象引用,那么A和B其實(shí)是已經(jīng)沒(méi)有用的垃圾對(duì)象了,但是他們的引用計(jì)數(shù)并不為0,那么此時(shí)就得通過(guò)GCRoot可達(dá)性來(lái)判斷它是否可以被回收了
上圖吧,文字解釋太蒼白無(wú)力


image.png

GC Root有哪些?

  • 虛擬機(jī)中引用的對(duì)象(局部變量引用的對(duì)象)
  • 方法區(qū)中類靜態(tài)屬性引用的對(duì)象
  • 方法區(qū)中常量引用對(duì)象
  • 本地方法棧中JNI引用對(duì)象
  • 活著的線程

那么現(xiàn)在來(lái)想想什么是內(nèi)存泄漏呢?

通俗點(diǎn)來(lái)說(shuō)就是,某個(gè)對(duì)象明明已經(jīng)沒(méi)有用了,但是它卻可達(dá)GCRoot,那么這時(shí)候,GC就無(wú)法對(duì)這個(gè)沒(méi)有用的對(duì)象進(jìn)行回收,就導(dǎo)致了內(nèi)存泄漏趁冈。

什么情況下會(huì)發(fā)生內(nèi)存泄漏呢?

舉兩個(gè)例子
\color{green}{例子1}
我們知道內(nèi)部類會(huì)持有外部類的引用,當(dāng)我們使用Handler時(shí),如果MyHandler不是靜態(tài)內(nèi)部類,那么可以看到AS會(huì)發(fā)出一個(gè)警告!加入TestActivity已經(jīng)關(guān)閉了,但是此時(shí)MyHandler的MessageQueue中還有未被執(zhí)行的Message,那么MyHandler并不會(huì)被銷毀,而且它還持有者TestActivity的引用,那么此時(shí)就造成了TestActivity的內(nèi)存泄漏

解決辦法
要么將MyHandler聲明為static的,要么將TestActivity使用WeakReference包裹起來(lái)!


leak.png

\color{green}{例子2}
Singleton.java

package com.taylor.androidinterview;

import android.content.Context;

/**
 * Copyright:AndroidInterview
 * Author: liyang <br>
 * Date:2019-10-07 20:19<br>
 * Desc: <br>
 */
public class Singleton {
    private static Singleton sInstance;
    private static Context mContext;

    private Singleton(Context context) {
        mContext = context;
    }

    public static Singleton getInstance(Context context) {
        if (sInstance == null) {
            synchronized (Singleton.class) {
                if (sInstance == null) {
                    sInstance = new Singleton(context);
                }
            }
        }
        return sInstance;
    }
}

TestActivity.java

package com.taylor.androidinterview;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;

import androidx.appcompat.app.AppCompatActivity;

public class TestActivity extends AppCompatActivity {
    private MyHandler myHandler;
    private Singleton mSingleton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        mSingleton = Singleton.getInstance(this);
        myHandler=new MyHandler();

        myHandler.postDelayed(() -> System.out.println("我被執(zhí)行了!!!"),100000000);

        findViewById(R.id.btnClose).setOnClickListener(v-> finish());
    }

    class MyHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
        }
    }
}

SIngleton是個(gè)單例類,他的內(nèi)部的mContext變量是static的,所以mContext是一個(gè)GCRoot,那么此時(shí)當(dāng)TestActivity關(guān)閉時(shí),由于Singleton的mContext是GCRoot并且持有了TestActivity,那么TestActivity并不能得到回收,同樣造成了內(nèi)存泄漏.
解決辦法,使用ApplicationContext代替Context,因?yàn)锳pplicationContext是和App生命周期一致的

其實(shí)AS已經(jīng)很強(qiáng)大了,如果你的代碼可能會(huì)導(dǎo)致內(nèi)存泄漏,大部分情況下AS都會(huì)給出警告的,只是很多人忽視警告而已

當(dāng)然android中可能導(dǎo)致內(nèi)存泄漏的情況還有很多,比如Activity銷毀了但是沒(méi)有解除監(jiān)聽(tīng),Activity銷毀了但是還有活著的線程等等

Android內(nèi)存泄漏如何檢測(cè)?

  • adb觀察法
  • LeakCanary等三方檢測(cè)庫(kù)
  • 使用Profiler分析檢測(cè)
  • 使用MAT進(jìn)行檢測(cè)

adb觀察法

ttt.gif

image.png

我在MainActivity中打開(kāi)了剛才寫(xiě)的TestActivity,然后就關(guān)閉了TestActivity,為了避免JVM沒(méi)有及時(shí)回收TestActivity,我又使用Profiler主動(dòng)進(jìn)行了一個(gè)垃圾回收!
此時(shí)我們使用adb shell dunpsys meminfo com.taylor.androidinterview -d命令查看下app的內(nèi)存情況

QQ20191007-210131@2x.png

Objects:
中羅列的就是當(dāng)前app中現(xiàn)在存活的實(shí)例
Views有36個(gè),AppContext有4個(gè),Activity有兩個(gè)

我們明明關(guān)閉了TestActivity,此時(shí)app中應(yīng)該只有一個(gè)Activity,但是由于TestActivity中使用Singleton和MyHandler導(dǎo)致了TestActivity內(nèi)存泄漏了

adb觀察法只能粗略的查看下內(nèi)存情況,如果想要追溯內(nèi)存泄漏的具體位置就得借助LeakCanary、Profiler和MAT這些工具了

LeakCanary 就不做過(guò)多介紹了

具體可以查看官方文檔http://square.github.io/leakcanary
,其實(shí)LeakCanary的原理和我們接下來(lái)要講的使用Profiler和MAT分析差不多,但是即便是使用LeakCanary還是會(huì)有一些情況它無(wú)法檢測(cè)到

LeakCanary原理:
LeakCanary會(huì)在Activity的onDestroy方法中取刃,主動(dòng)調(diào)用 GC坯辩,并利用ReferenceQueue+WeakReference馁龟,來(lái)判斷是否有釋放不掉的引用,然后結(jié)合dump memory的hpof文件, 用HaHa分析出泄漏地方濒翻。

使用Profiler分析檢測(cè)

接下來(lái)我們使用Profiler來(lái)進(jìn)行分析
我又反復(fù)打開(kāi)TestActivity然后又關(guān)閉掉兩次,
可以看到我選取的app內(nèi)存信息的時(shí)間點(diǎn)是在TestActivity銷毀之后,但是此時(shí)可以看到App中任然有3個(gè)TestActivity實(shí)例\color{blue}{(通常點(diǎn)擊右側(cè)InstanceView中的對(duì)象實(shí)例,下方應(yīng)該會(huì)展示出該實(shí)例的Call Stack調(diào)用棧信息的,你基本上可以在調(diào)用棧信息中找到是哪個(gè)類中的哪一行代碼導(dǎo)致的這個(gè)TestActivity的內(nèi)存泄漏!但是我點(diǎn)擊TestActivity下方并沒(méi)有出現(xiàn)調(diào)用棧信息,不知道是不是我這個(gè)版本AS的bug???)}
Profiler的功能非常強(qiáng)大,你可以用它來(lái)分析網(wǎng)絡(luò),分析性能,分析內(nèi)存情況等,絕對(duì)是分析查找問(wèn)題的好幫手
profiler的具體使用請(qǐng)查看google的官方文檔https://developer.android.google.cn/studio/profile/memory-profiler

image.png

使用MAT進(jìn)行檢測(cè)分析

MAT是Memory Analysis Tools的縮寫(xiě),從名稱就可以看出他是專門(mén)用來(lái)分析內(nèi)存的工具

  • 第一步:接下來(lái)我們使用profiler dump內(nèi)存快照并保存為memory-mat.hprof
    image.png
image.png

MAT可以解析Java SE HPROF 格式的.hprof文件,但是無(wú)法解析android格式的.hprof文件,所以我們需要android_sdk/platform-tools/ hrpof-conv工具將.hprof文件轉(zhuǎn)換為MAT可以分析的格式

如果你沒(méi)有將hprof-conv工具配置到全局變量里那么就需要到它所在的文件夾內(nèi)才能使用hprof-conv命令

  • 第二步 轉(zhuǎn)換hprof文件格式
    hprof-conv <原h(huán)prof文件名 ><轉(zhuǎn)換后的hprof文件名>
liyangdeMacBook-Pro:~ liyang$ cd /Users/liyang/Library/Android/sdk/platform-tools
liyangdeMacBook-Pro:platform-tools liyang$ hprof-conv /Users/liyang/Downloads/work/AndroidInterview/memory-mat.hprof /Users/liyang/Downloads/work/AndroidInterview/memory-mat-conv.hprof

接下來(lái)我們就可以使用MAT對(duì)堆存快照進(jìn)行分析,精確內(nèi)存泄漏的位置了

  • 第三步 使用MAT打開(kāi)轉(zhuǎn)換后的memory-mat-conv.hprof文件


    image.png

打開(kāi)后,我們先點(diǎn)擊Overview概覽這個(gè)tab


image.png

Overview界面的下方actions這一列中有四個(gè)選項(xiàng)

功能名 作用
histogram 羅列出每個(gè)class類中的實(shí)例個(gè)數(shù)等情況(我們分析內(nèi)存泄漏使用的就是這個(gè)功能)
DominatorTree 羅列出那些一直存活的占用內(nèi)存較大的對(duì)象(如果你的app發(fā)生的OutOfMemory可以使用這個(gè)功能進(jìn)行分析,從那些過(guò)于龐大的對(duì)象中找出元兇)
Top Consumer 可以根據(jù)class或者package進(jìn)行分組,打印出那些最耗費(fèi)性能的對(duì)象(如果你覺(jué)得你的項(xiàng)目運(yùn)行時(shí)比較卡頓,可以使用這個(gè)功能進(jìn)行分析查找)
Duplicate Classes 檢測(cè)被多個(gè)ClassLoader加載的類
  • 第四步 接下來(lái)我們使用Histogram功能查看下我們的app中的實(shí)例對(duì)象情況
image.png

打開(kāi)Histogram后,它默認(rèn)是group by class,我們選擇group by package 找到我們的app

image.png

通過(guò)按照package來(lái)分組,我們可以很快找到自己的app,從上圖可以看到,何Profiler中的情況一樣TestActivity仍然有3個(gè)實(shí)例,也就是我們每打開(kāi)一次TestActivity都會(huì)有一個(gè)實(shí)例內(nèi)存泄漏了

上圖中被我圈住的Shallow Heap和Retained Heap是代表什么意思呢?

名稱 代表什么意思呢
Shallow Heap 對(duì)象本身占用內(nèi)存的大小屁柏,不包含其引用的對(duì)象。(單位是字節(jié))
Retained Heap 是對(duì)象及被其引用的對(duì)象的總大小,如果該對(duì)象被釋放了進(jìn)而可以釋放的大小(單位是字節(jié))
  • 第五步 接下來(lái)我們查看下TestActivity都被誰(shuí)引用而導(dǎo)致泄漏的呢?


    image.png

選中TestActivity,右鍵可以看到一系列的功能,有List Objects/Show objects by class/...

List Objects和Show objects by class功能差不多
前者是按照實(shí)例分組,比如這里TestActivity有3個(gè)實(shí)例,會(huì)羅列出三個(gè)實(shí)例
后者是按照類來(lái)分組,那么久會(huì)列出TestActivity這一個(gè)類

這里重點(diǎn)應(yīng)該介紹with outgoing reference和with incoming reference
with outgoing reference看字面意思大概也可以知道是這個(gè)對(duì)象被誰(shuí)引用了
with incoming reference 也就是這個(gè)對(duì)象引用了誰(shuí)
這里因?yàn)門(mén)estActivity內(nèi)存泄漏了,當(dāng)然我們要看看是誰(shuí)持有了它導(dǎo)致它內(nèi)存泄漏的,選outgoing

image.png

選擇了outgoing后,根據(jù)上圖可以看到TestActivity被這么多對(duì)象引用了,那么怎么找出元兇呢?
\color{red}{上面我們講過(guò)了,判斷一個(gè)對(duì)象可不可以被GC回收,要看這個(gè)對(duì)象向上追溯引用能否一直追溯到GCRoot}
那么我們直接選Path To GC Roots,然后看到選擇之后會(huì)出現(xiàn)有一些選項(xiàng),排除弱引用, 排除軟引用...

image.png

我們知道java中有四種引用類型

引用類型 介紹
強(qiáng)引用(我們直接new出來(lái)的對(duì)象都是強(qiáng)引用) 強(qiáng)引用有三個(gè)特點(diǎn)(一)強(qiáng)引用可以直接訪問(wèn)目標(biāo)對(duì)象有送。(二)強(qiáng)引用所指向的對(duì)象在任何時(shí)候都不會(huì)被系統(tǒng)回收淌喻。JVM寧愿拋出OOM異常,也不會(huì)回收強(qiáng)引用所指向的對(duì)象雀摘。(三)強(qiáng)引用可能導(dǎo)致內(nèi)存泄漏裸删。
軟引用(SoftReference) 軟引用是除了強(qiáng)引用外,最強(qiáng)的引用類型阵赠⊙乃可以通過(guò)java.lang.ref.SoftReference使用軟引用。一個(gè)持有軟引用的對(duì)象清蚀,不會(huì)被JVM很快回收匕荸,JVM會(huì)根據(jù)當(dāng)前堆的使用情況來(lái)判斷何時(shí)回收。當(dāng)堆使用率臨近閾值時(shí)枷邪,才會(huì)去回收軟引用的對(duì)象榛搔。因此,軟引用可以用于實(shí)現(xiàn)對(duì)內(nèi)存敏感的高速緩存东揣。
弱引用(WeakReference) 弱引用是一種比軟引用較弱的引用類型践惑。弱引用對(duì)象的存在不會(huì)阻止它所指向的對(duì)象變被垃圾回收器回收。在系統(tǒng)GC時(shí)嘶卧,只要發(fā)現(xiàn)弱引用尔觉,不管系統(tǒng)堆空間是否足夠,都會(huì)將對(duì)象進(jìn)行回收芥吟。在java中侦铜,可以用java.lang.ref.WeakReference實(shí)例來(lái)保存對(duì)一個(gè)Java對(duì)象的弱引用。
虛引用(PhantomReference) 虛引用是所有類型中最弱的一個(gè)运沦。一個(gè)持有虛引用的對(duì)象泵额,和沒(méi)有引用幾乎是一樣的,隨時(shí)可能被垃圾回收器回收携添。當(dāng)試圖通過(guò)虛引用的get()方法取得強(qiáng)引用時(shí),總是會(huì)失敗篓叶。并且烈掠,虛引用必須和引用隊(duì)列一起使用羞秤,它的作用在于跟蹤垃圾回收過(guò)程。

根據(jù)強(qiáng)度排個(gè)序
強(qiáng)引用>軟引用>弱引用>虛引用

我們過(guò)濾掉軟引用,弱引用和虛引用再看看
選擇了exclude all phatom/weak/soft etc. reference之后

image.png

可以看到,TestActivity被兩個(gè)GC Roots引用了,一個(gè)是Singleton中的mContext變量因?yàn)槭庆o態(tài)的,另一個(gè)就是mHandler,是非靜態(tài)內(nèi)部類
罪魁禍?zhǔn)渍业搅?/strong>

android中如何盡量避免內(nèi)存泄漏呢?

大致可以總結(jié)一些情況

  • getSystemService的時(shí)候左敌,應(yīng)避免使用activity的context瘾蛋,而是使用application的context
  • 單例模式中盡量避免使用context,如果一定要使用應(yīng)使用context.getApplicationContext來(lái)代替
  • 如果使用觀察者模式時(shí),在onCreate或者onStart中注冊(cè)了監(jiān)聽(tīng),要記得在對(duì)應(yīng)的生命周期中解除監(jiān)聽(tīng)
  • 非靜態(tài)內(nèi)部類矫限、匿名內(nèi)部類會(huì)持有外部類的實(shí)例引用哺哼,導(dǎo)致泄漏〉鸱纾可以在不需要的時(shí)候主動(dòng)置空或者使用弱引用
  • 在Runnable中做操作時(shí)一定要小心,如果Activity或Fragment銷毀了,及時(shí)停止線程
  • 使用資源時(shí)(比如Cursor取董、File、Bitmap无宿、視頻茵汰、音頻等)及時(shí)關(guān)閉
  • Glide.with(context)這個(gè)context不可以亂用
  • ...歡迎補(bǔ)充
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市孽鸡,隨后出現(xiàn)的幾起案子蹂午,更是在濱河造成了極大的恐慌,老刑警劉巖彬碱,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件豆胸,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡巷疼,警方通過(guò)查閱死者的電腦和手機(jī)晚胡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)皮迟,“玉大人搬泥,你說(shuō)我怎么就攤上這事》幔” “怎么了忿檩?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)爆阶。 經(jīng)常有香客問(wèn)我燥透,道長(zhǎng),這世上最難降的妖魔是什么辨图? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任班套,我火速辦了婚禮,結(jié)果婚禮上故河,老公的妹妹穿的比我還像新娘吱韭。我一直安慰自己,他們只是感情好鱼的,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布理盆。 她就那樣靜靜地躺著痘煤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪猿规。 梳的紋絲不亂的頭發(fā)上衷快,一...
    開(kāi)封第一講書(shū)人閱讀 51,155評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音姨俩,去河邊找鬼蘸拔。 笑死,一個(gè)胖子當(dāng)著我的面吹牛环葵,可吹牛的內(nèi)容都是我干的调窍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼积担,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼陨晶!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起帝璧,我...
    開(kāi)封第一講書(shū)人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤先誉,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后的烁,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體褐耳,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年渴庆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了铃芦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡襟雷,死狀恐怖刃滓,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情耸弄,我是刑警寧澤咧虎,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站计呈,受9級(jí)特大地震影響砰诵,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜捌显,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一茁彭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧扶歪,春花似錦理肺、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)贪薪。三九已至媳禁,卻和暖如春眠副,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背竣稽。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工囱怕, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人毫别。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓娃弓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親岛宦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子台丛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

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